use crate::{mapper::*, nes_err, NesResult};
use enum_dispatch::enum_dispatch;
use std::{
collections::VecDeque,
io::{Read, Write},
};
const SAVE_FILE_MAGIC_LEN: usize = 8;
const SAVE_FILE_MAGIC: [u8; SAVE_FILE_MAGIC_LEN] = *b"TETANES\x1a";
const VERSION: u8 = 0;
pub fn write_save_header<F: Write>(fh: &mut F) -> NesResult<()> {
SAVE_FILE_MAGIC.save(fh)?;
VERSION.save(fh)
}
pub fn validate_save_header<F: Read>(fh: &mut F) -> NesResult<()> {
let mut magic = [0u8; SAVE_FILE_MAGIC_LEN];
magic.load(fh)?;
if magic != SAVE_FILE_MAGIC {
nes_err!("invalid save file format")
} else {
let mut version = 0u8;
version.load(fh)?;
if version != VERSION {
nes_err!(
"invalid save file version. current: {}, save file: {}",
VERSION,
version,
)
} else {
Ok(())
}
}
}
#[enum_dispatch(MapperType)]
pub trait Savable {
fn save<F: Write>(&self, _fh: &mut F) -> NesResult<()> {
Ok(())
}
fn load<F: Read>(&mut self, _fh: &mut F) -> NesResult<()> {
Ok(())
}
}
impl Savable for bool {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&[*self as u8])?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0; 1];
fh.read_exact(&mut bytes)?;
*self = bytes[0] > 0;
Ok(())
}
}
impl Savable for char {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
self.to_string().save(fh)?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut s = " ".to_string();
s.load(fh)?;
Ok(())
}
}
impl Savable for i8 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0; 1];
fh.read_exact(&mut bytes)?;
*self = i8::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for u8 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0; 1];
fh.read_exact(&mut bytes)?;
*self = u8::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for i16 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0; 2];
fh.read_exact(&mut bytes)?;
*self = i16::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for u16 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0; 2];
fh.read_exact(&mut bytes)?;
*self = u16::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for i32 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0u8; 4];
fh.read_exact(&mut bytes)?;
*self = i32::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for u32 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0u8; 4];
fh.read_exact(&mut bytes)?;
*self = u32::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for f32 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
self.to_bits().save(fh)?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut val = 0u32;
val.load(fh)?;
*self = f32::from_bits(val);
Ok(())
}
}
impl Savable for u64 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
fh.write_all(&self.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0u8; 8];
fh.read_exact(&mut bytes)?;
*self = u64::from_be_bytes(bytes);
Ok(())
}
}
impl Savable for f64 {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
self.to_bits().save(fh)
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut val = 0u64;
val.load(fh)?;
*self = f64::from_bits(val);
Ok(())
}
}
impl Savable for usize {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
let val = *self as u32;
fh.write_all(&val.to_be_bytes())?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut bytes = [0u8; 4];
fh.read_exact(&mut bytes)?;
let val = u32::from_be_bytes(bytes);
*self = val as usize;
Ok(())
}
}
impl<T: Savable> Savable for [T] {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
let len: usize = self.len();
if len > std::u32::MAX as usize {
return nes_err!("Unable to save more than {} bytes", std::u32::MAX);
}
let len = len as u32;
len.save(fh)?;
for i in self.iter() {
i.save(fh)?;
}
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut len = 0u32;
len.load(fh)?;
if len != self.len() as u32 {
panic!(
"Array read len does not match. Got {}, expected {}",
len,
self.len() as u32
);
}
for i in 0..len {
self[i as usize].load(fh)?;
}
Ok(())
}
}
impl<T: Savable + Default> Savable for Vec<T> {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
let len: usize = self.len();
if len > std::u32::MAX as usize {
return nes_err!("Unable to save more than {} bytes", std::u32::MAX);
}
let len = len as u32;
len.save(fh)?;
for i in self.iter() {
i.save(fh)?;
}
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut len = 0u32;
len.load(fh)?;
if self.is_empty() {
*self = Vec::with_capacity(len as usize);
for _ in 0..len {
self.push(T::default());
}
} else if len != self.len() as u32 {
return nes_err!(
"Vec read len does not match. Got {}, expected {}",
len,
self.len() as u32
);
}
for i in 0..len {
self[i as usize].load(fh)?;
}
Ok(())
}
}
impl<T: Savable + Default> Savable for VecDeque<T> {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
let len: usize = self.len();
if len > std::u32::MAX as usize {
return nes_err!("Unable to save more than {} bytes", std::u32::MAX);
}
let len = len as u32;
len.save(fh)?;
for i in self.iter() {
i.save(fh)?;
}
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut len = 0u32;
len.load(fh)?;
if self.is_empty() {
*self = VecDeque::with_capacity(len as usize);
for _ in 0..len {
self.push_back(T::default());
}
} else if len != self.len() as u32 {
return nes_err!(
"VecDeque read len does not match. Got {}, expected {}",
len,
self.len() as u32
);
}
for i in 0..len {
self[i as usize].load(fh)?;
}
Ok(())
}
}
impl<T: Savable + Default> Savable for Option<T> {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
match self {
Some(t) => {
1u8.save(fh)?;
t.save(fh)?;
}
None => 0u8.save(fh)?,
}
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut some = 0u8;
some.load(fh)?;
*self = match some {
0 => None,
1 => {
let mut val = T::default();
val.load(fh)?;
Some(val)
}
_ => return nes_err!("invalid Option<T> read"),
};
Ok(())
}
}
impl Savable for String {
fn save<F: Write>(&self, fh: &mut F) -> NesResult<()> {
self.as_bytes().save(fh)?;
Ok(())
}
fn load<F: Read>(&mut self, fh: &mut F) -> NesResult<()> {
let mut len = 0u32;
len.load(fh)?;
if self.is_empty() {
let mut bytes = Vec::with_capacity(len as usize);
bytes.load(fh)?;
*self = String::from_utf8(bytes)?;
} else if len != self.len() as u32 {
return nes_err!(
"String read len does not match. Got {}, expected {}",
len,
self.len() as u32
);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn save_header() {
let mut file = Vec::new();
assert!(write_save_header(&mut file).is_ok(), "write save header");
assert!(
validate_save_header(&mut file.as_slice()).is_ok(),
"validate save header"
);
}
}