use std::io::{Read, Write};
use anyhow::Result;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::{Db, MAX_KEY_SIZE};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Cell {
Full(Vec<u8>),
Partial(Vec<u8>, u64, u64),
}
pub fn write_cell(mut buf: impl Write, cell: &Cell) {
match cell {
Cell::Full(vec) => {
buf.write_u16::<BigEndian>(vec.len() as u16).unwrap();
buf.write_all(vec).unwrap();
}
Cell::Partial(vec, page, len) => {
buf.write_u16::<BigEndian>(MAX_KEY_SIZE).unwrap();
buf.write_all(vec).unwrap();
buf.write_u64::<BigEndian>(*page).unwrap();
buf.write_u64::<BigEndian>(*len).unwrap();
}
}
}
pub fn read_cell<R: Read>(reader: &mut R) -> std::io::Result<Cell> {
let len = reader.read_u16::<BigEndian>()?;
if len == MAX_KEY_SIZE {
let mut buf = vec![0; len as usize - 16];
reader.read_exact(&mut buf)?;
let overflow_page = reader.read_u64::<BigEndian>().unwrap();
let overflow_length = reader.read_u64::<BigEndian>().unwrap();
Ok(Cell::Partial(buf, overflow_page, overflow_length))
} else {
let mut buf = vec![0; len as usize];
reader.read_exact(&mut buf)?;
Ok(Cell::Full(buf))
}
}
pub fn encode_cell(store: &mut Db, v: Vec<u8>) -> Result<Cell> {
Ok(if v.len() >= MAX_KEY_SIZE as usize {
let rest = v[MAX_KEY_SIZE as usize - 16..].to_vec();
let overflow_length = rest.len();
let overflow_page = store.append_overflow_pages(rest)?;
Cell::Partial(
v[0..MAX_KEY_SIZE as usize - 16].to_vec(),
overflow_page,
overflow_length as u64,
)
} else {
Cell::Full(v)
})
}
pub fn fetch_cell(store: &mut Db, cell: &Cell) -> Result<Vec<u8>> {
Ok(match &cell {
Cell::Full(vec) => vec.clone(),
Cell::Partial(part_vec, overflow_page, overflow_length) => [
part_vec.clone(),
store.read_overflow_pages(*overflow_page, *overflow_length)?,
]
.concat(),
})
}
pub fn free_cell(store: &mut Db, cell: &Cell) -> Result<()> {
match &cell {
Cell::Full(..) => Ok(()),
Cell::Partial(_, overflow_page, _) => store.free_overflow_pages(*overflow_page),
}
}