use integer_encoding::VarInt;
use std::convert::TryFrom;
use super::errors::{ReadError, TableReadResult};
pub(crate) const BLOCK_HANDLE_MAX_ENCODED_LENGTH_BYTES: u64 = 10 + 10;
#[derive(Debug, Eq, PartialEq)]
pub(crate) struct BlockHandle {
offset: u64,
size: u64,
}
impl BlockHandle {
pub fn new(offset: u64, size: u64) -> Self {
Self { offset, size }
}
pub fn get_offset(&self) -> u64 {
self.offset
}
pub fn get_size(&self) -> u64 {
self.size
}
pub fn deserialize(buf: &[u8]) -> TableReadResult<(BlockHandle, usize)> {
let maybe_decoded_offset = u64::decode_var(buf);
if maybe_decoded_offset.is_none() {
return Err(ReadError::FailedToParse(
"Failed to deserialize the block handle offset.".to_string(),
));
}
let (offset, offset_occupied_length) = maybe_decoded_offset.unwrap();
let maybe_decoded_size = u64::decode_var(&buf[offset_occupied_length..]);
if maybe_decoded_size.is_none() {
return Err(ReadError::FailedToParse(
"Failed to deserialize the block handle offset.".to_string(),
));
}
let (size, size_occuppied_length) = maybe_decoded_size.unwrap();
let bytes_read = offset_occupied_length + size_occuppied_length;
Ok((BlockHandle::new(offset, size), bytes_read))
}
}
impl TryFrom<&[u8]> for BlockHandle {
type Error = ReadError;
fn try_from(value: &[u8]) -> TableReadResult<BlockHandle> {
let (handle, _bytes_read) = BlockHandle::deserialize(value)?;
Ok(handle)
}
}
impl TryFrom<&Vec<u8>> for BlockHandle {
type Error = ReadError;
fn try_from(value: &Vec<u8>) -> TableReadResult<BlockHandle> {
let (handle, _bytes_read) = BlockHandle::deserialize(value)?;
Ok(handle)
}
}
impl From<&BlockHandle> for Vec<u8> {
fn from(value: &BlockHandle) -> Vec<u8> {
let encoded_offset = value.offset.encode_var_vec();
let encoded_size = value.size.encode_var_vec();
[encoded_offset, encoded_size].concat()
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn can_get_properties() {
let block_handle = BlockHandle::new(80, 2_000);
assert_eq!(block_handle.get_offset(), 80);
assert_eq!(block_handle.get_size(), 2_000);
}
#[test]
fn can_be_serialized_and_deserialized() {
let block_handle = BlockHandle::new(80, 2_000);
let serialized = Vec::<u8>::from(&block_handle);
let deserialized_from_slice = BlockHandle::try_from(serialized.as_slice()).unwrap();
let deserialized_from_ref = BlockHandle::try_from(&serialized).unwrap();
assert_eq!(block_handle, deserialized_from_slice);
assert_eq!(block_handle, deserialized_from_ref);
}
}