Skip to main content

fcb_core/static_btree/
entry.rs

1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use chrono::{DateTime, Utc};
3use ordered_float::OrderedFloat;
4
5use crate::static_btree::error::Result;
6use crate::FixedStringKey;
7use crate::Key;
8use std::cmp::Ordering;
9use std::fmt::Debug;
10use std::io::{Read, Write};
11use std::mem;
12
13/// The type associated with each key in the tree.
14/// Currently fixed to u64, assuming byte offsets as values.
15/// For leaf nodes except the last one, the offset is the byte offset of actual data. For the last entry of a leaf node, the offset is the byte offset of the next leaf node as it's B+Tree.
16/// For internal nodes, the offset is the byte offset of the first key of the child node.
17pub type Offset = u64;
18
19/// Constant for the size of the Value type in bytes.
20pub const OFFSET_SIZE: usize = mem::size_of::<Offset>();
21
22/// Represents a Key-Value pair. Stored in leaf nodes and used as input for building.
23// Remove the generic V, use the concrete Value type alias directly.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct Entry<K: Key> {
26    /// The key part of the entry.
27    pub key: K,
28    /// The value part of the entry (u64 offset).
29    pub offset: Offset, // Use the Value type alias directly
30}
31
32// Update the impl block to only use the K generic parameter
33impl<K: Key> Entry<K> {
34    /// The size of the value part in bytes (u64).
35    const OFFSET_SIZE: usize = mem::size_of::<Offset>();
36    /// The total size of the entry when serialized.
37    pub const SERIALIZED_SIZE: usize = K::SERIALIZED_SIZE + Self::OFFSET_SIZE;
38
39    pub fn new(key: K, offset: Offset) -> Self {
40        Self { key, offset }
41    }
42
43    /// Serializes the entire entry (key followed by value) to a writer.
44    /// Assumes little-endian encoding for the `Value`.
45    pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
46        let mut written_bytes = 0;
47        written_bytes += self.key.write_to(writer)?;
48
49        writer.write_u64::<LittleEndian>(self.offset)?;
50        written_bytes += Self::OFFSET_SIZE;
51        Ok(written_bytes)
52    }
53
54    /// Deserializes an entire entry from a reader.
55    /// Assumes little-endian encoding for the `Value`.
56    pub fn from_reader<R: Read>(reader: &mut R) -> Result<Self> {
57        let key = K::read_from(reader)?;
58        let offset = reader.read_u64::<LittleEndian>()?;
59        Ok(Entry { key, offset })
60    }
61
62    pub fn from_bytes(raw: &[u8]) -> Result<Self> {
63        let key = K::from_bytes(&raw[0..K::SERIALIZED_SIZE])?;
64        let offset = Offset::from_bytes(&raw[K::SERIALIZED_SIZE..])?;
65        Ok(Entry { key, offset })
66    }
67
68    pub fn key_size() -> usize {
69        K::SERIALIZED_SIZE
70    }
71}
72
73// Update ordering implementations
74impl<K: Key> PartialOrd for Entry<K> {
75    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76        self.key.partial_cmp(&other.key)
77    }
78}
79
80impl<K: Key> Ord for Entry<K> {
81    fn cmp(&self, other: &Self) -> Ordering {
82        self.key.cmp(&other.key)
83    }
84}
85
86pub enum TypedEntry {
87    StringKey20(Entry<FixedStringKey<20>>),
88    StringKey50(Entry<FixedStringKey<50>>),
89    StringKey100(Entry<FixedStringKey<100>>),
90    Int32(Entry<i32>),
91    Int64(Entry<i64>),
92    UInt32(Entry<u32>),
93    UInt64(Entry<u64>),
94    Float32(Entry<OrderedFloat<f32>>),
95    Float64(Entry<OrderedFloat<f64>>),
96    Bool(Entry<bool>),
97    DateTime(Entry<DateTime<Utc>>),
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::static_btree::error::Error;
104    use crate::Key;
105    use std::io::Cursor;
106
107    #[test]
108    fn test_entry_serialization_deserialization() {
109        let entry = Entry {
110            // No V generic needed here
111            key: 12345,
112            offset: 9876543210,
113        };
114
115        let mut buffer = Vec::new();
116        entry.write_to(&mut buffer).expect("write should succeed");
117
118        assert_eq!(
119            buffer.len(),
120            i32::SERIALIZED_SIZE + mem::size_of::<Offset>()
121        );
122        assert_eq!(buffer.len(), Entry::<i32>::SERIALIZED_SIZE); // Update const access
123
124        let mut cursor = Cursor::new(buffer);
125        let deserialized_entry =
126            Entry::<i32>::from_reader(&mut cursor).expect("read should succeed"); // Update type
127
128        assert_eq!(entry, deserialized_entry);
129    }
130
131    #[test]
132    fn test_entry_ordering() {
133        let entry1 = Entry {
134            // No V generic
135            key: 10,
136            offset: 100,
137        };
138        let entry2 = Entry {
139            // No V generic
140            key: 20,
141            offset: 50,
142        };
143        let entry3 = Entry {
144            // No V generic
145            key: 10,
146            offset: 200,
147        };
148
149        assert!(entry1 < entry2);
150        assert!(entry2 > entry1);
151        assert_eq!(entry1.cmp(&entry3), Ordering::Equal);
152        assert_eq!(entry1.partial_cmp(&entry3), Some(Ordering::Equal));
153    }
154
155    #[test]
156    fn test_entry_read_error_short_read() {
157        let mut short_buffer = vec![0u8; Entry::<i32>::SERIALIZED_SIZE - 1]; // Update const access
158        let mut cursor = Cursor::new(&mut short_buffer);
159        let result = Entry::<i32>::from_reader(&mut cursor); // Update type
160        assert!(result.is_err());
161        match result.err().unwrap() {
162            Error::IoError(e) => assert_eq!(e.kind(), std::io::ErrorKind::UnexpectedEof),
163            _ => panic!("expected io error"),
164        }
165    }
166}