use std::io::Result as IoResult;
use std::io::Seek;
use std::io::Write;
use std::{fs::File, io::SeekFrom, path::PathBuf};
#[derive(Debug, Clone, Default)]
pub struct Bytes {
pub data: Vec<(u64, Vec<u8>)>,
pub offset_value: u64,
pub byte_sequence: Vec<u8>,
}
impl Bytes {
pub fn new() -> Self {
Self {
data: vec![],
offset_value: 0,
byte_sequence: vec![],
}
}
pub fn finalize(&mut self) {
if !self.byte_sequence.is_empty() {
let new_offset = self.offset_value + (self.byte_sequence.len() as u64);
let byte_sequence = std::mem::take(&mut self.byte_sequence);
self.data.push((self.offset_value, byte_sequence));
self.offset_value = new_offset;
}
}
pub fn set_offset(&mut self, offset: u64) {
self.finalize();
self.offset_value = offset;
}
pub fn add_bytes(&mut self, bytes: &[u8]) {
self.byte_sequence.extend_from_slice(bytes);
}
pub fn add_byte(&mut self, byte: u8) {
self.byte_sequence.push(byte);
}
pub fn get_offset(&mut self) -> u64 {
self.offset_value + (self.byte_sequence.len() as u64)
}
pub fn get_bytes(&mut self) -> Vec<u8> {
self.finalize();
let mut all_bytes = vec![];
for (offset, bytes) in &self.data {
let capacity = *offset + (bytes.len() as u64);
if capacity > (all_bytes.len() as u64) {
all_bytes.resize(capacity as usize, 0u8);
}
for index in 0..bytes.len() {
all_bytes[*offset as usize + index] = bytes[index];
}
}
all_bytes
}
pub fn write_bytes(&mut self, destination: PathBuf) -> IoResult<()> {
self.finalize();
let mut file = File::create(destination)?;
for (offset, bytes) in &self.data {
file.seek(SeekFrom::Start(*offset))?;
file.write_all(bytes)?;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use std::{fs::File, io::Read, path::PathBuf};
use super::Bytes;
#[test]
fn trivial_test_1() {
let mut bytes = Bytes::new();
assert_eq!(bytes.get_offset(), 0);
assert_eq!(bytes.get_bytes(), vec![]);
}
#[test]
fn trivial_test_2() {
let mut bytes = Bytes::new();
bytes.finalize();
bytes.add_byte(0);
assert_eq!(bytes.get_offset(), 1);
assert_eq!(bytes.get_bytes(), vec![0u8]);
}
#[test]
fn file_test_1() -> std::io::Result<()> {
let mut bytes = Bytes::new();
bytes.add_bytes(b"Erase me!");
bytes.finalize();
bytes.write_bytes(PathBuf::from("eraseme.txt"))?;
let mut file = File::open("eraseme.txt").unwrap();
let mut content = vec![];
file.read_to_end(&mut content)?;
assert_eq!("Erase me!".as_bytes(), content);
std::fs::remove_file("eraseme.txt")?;
Ok(())
}
}