use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use instruction::Instruction;
use rmps::{Deserializer, Serializer};
use serde::{Deserialize, Serialize};
use std::{
fs::File, io::{Read, Write}, path::Path,
};
use typedef::*;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Program {
pub target_version: String,
pub system_id: String,
pub instructions: Vec<Instruction>,
pub mem_pages: Option<u8>,
pub entry_point: Address,
}
impl Program {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Program> {
let mut file = File::open(path)?;
let mut gz_buf = Vec::new();
file.read_to_end(&mut gz_buf)?;
let res = Self::from_vec(gz_buf)?;
Ok(res)
}
pub fn from_vec(vec: Vec<u8>) -> Result<Program> {
let mut decoder = GzDecoder::new(&vec[..]);
let mut msgpack_buf = Vec::new();
decoder.read_to_end(&mut msgpack_buf)?;
let mut de = Deserializer::new(&msgpack_buf[..]);
let res = Deserialize::deserialize(&mut de)?;
Ok(res)
}
pub fn to_vec(&self) -> Result<Vec<u8>> {
let mut msgpack_buf = Vec::new();
self.serialize(&mut Serializer::new(&mut msgpack_buf))?;
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(&msgpack_buf[..])?;
let gz_buf = encoder.finish()?;
Ok(gz_buf)
}
pub fn save_as<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let gz_buf = self.to_vec()?;
let mut file = File::create(path)?;
file.write_all(&gz_buf[..])?;
file.flush()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{distributions::Standard, thread_rng, Rng};
use std::fs;
#[test]
fn save_and_load() {
let mut rng = thread_rng();
let file_name = format!("test.{}", ROM_FILE_EXTENSION);
let program = Program {
target_version: "bogus_version".into(),
system_id: "bogus_system".into(),
instructions: rng.sample_iter(&Standard).take(100).collect(),
mem_pages: Some(1),
entry_point: 0,
};
program.save_as(file_name.clone()).unwrap();
let loaded_program = Program::from_file(file_name.clone()).unwrap();
fs::remove_file(file_name.clone()).unwrap();
assert_eq!(program.target_version, loaded_program.target_version);
assert_eq!(program.system_id, loaded_program.system_id);
assert_eq!(program.mem_pages, loaded_program.mem_pages);
}
}