use std::io::{self, Read, Seek, SeekFrom, Take, Write};
use log::debug;
use serde_pickle::Value;
use crate::{RpaError, RpaResult};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Record {
pub start: u64,
pub length: u64,
pub prefix: Option<Vec<u8>>,
}
impl Record {
pub fn new(start: u64, length: u64, prefix: Option<Vec<u8>>, key: Option<u64>) -> Self {
let (start, length) = match key {
Some(key) => (start ^ key, length ^ key),
None => (start, length),
};
Self {
start,
length,
prefix,
}
}
pub fn from_value(value: Value, key: Option<u64>) -> RpaResult<Self> {
debug!("Parsing index from value: {value:?}");
let mut iter = match value {
Value::List(values) => {
let mut iter = values.into_iter();
match iter.next() {
Some(Value::List(values)) => values.into_iter(),
_ => return Err(RpaError::FormatRecord),
}
}
_ => return Err(RpaError::FormatRecord),
};
match (iter.next(), iter.next(), iter.next()) {
(Some(Value::I64(start)), Some(Value::I64(length)), None) => {
Ok(Self::new(start as u64, length as u64, None, key))
}
(Some(Value::I64(start)), Some(Value::I64(length)), Some(Value::Bytes(prefix))) => {
Ok(Self::new(start as u64, length as u64, Some(prefix), key))
}
_ => Err(RpaError::FormatRecord),
}
}
pub fn into_value(self) -> Value {
debug!(
"Creating value from index: [{}, {}, {:?}]",
self.start, self.length, self.prefix
);
let mut values = vec![
Value::I64(self.start as i64),
Value::I64(self.length as i64),
];
if let Some(prefix) = self.prefix {
values.push(Value::Bytes(prefix));
}
Value::List(vec![Value::List(values)])
}
}
impl Record {
fn actual_length(&self) -> u64 {
self.length - self.prefix.as_ref().map(|v| v.len()).unwrap_or(0) as u64
}
pub fn scope<'i, 'r, R: Seek + Read>(
&'i self,
reader: &'r mut R,
) -> io::Result<Take<&'r mut R>> {
reader.seek(SeekFrom::Start(self.start))?;
let take = reader.by_ref().take(self.actual_length());
Ok(take)
}
pub fn copy_section<'r, 'w, R, W>(
&'r self,
reader: &'r mut R,
writer: &'w mut W,
) -> io::Result<u64>
where
R: Seek + Read,
W: Write,
{
debug!(
"Copying index bytes starting {} of length {}",
self.start,
self.actual_length()
);
let mut scope = self.scope(reader)?;
if let Some(prefix) = self.prefix.as_ref() {
debug!("Writing prefix: {} bytes", prefix.len());
writer.write_all(&prefix[..])?;
}
io::copy(&mut scope, writer)
}
}