1use std::error::Error;
2use std::fmt::{Display, Formatter};
3
4const SAVE_STATE_MAGIC: &[u8; 8] = b"NESSTAT\0";
5const SAVE_STATE_VERSION: u32 = 1;
6
7#[derive(Debug, PartialEq, Eq)]
8pub enum SaveStateError {
9 InvalidMagic,
10 UnsupportedVersion(u32),
11 UnexpectedEof,
12 TrailingData,
13 NoCartridge,
14 MapperMismatch { expected: u16, actual: u16 },
15 InvalidData(&'static str),
16}
17
18impl Display for SaveStateError {
19 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
20 match self {
21 Self::InvalidMagic => f.write_str("save state header is invalid"),
22 Self::UnsupportedVersion(version) => {
23 write!(f, "save state version {} is not supported", version)
24 }
25 Self::UnexpectedEof => f.write_str("save state ended unexpectedly"),
26 Self::TrailingData => f.write_str("save state contains trailing bytes"),
27 Self::NoCartridge => f.write_str("save state requires an inserted cartridge"),
28 Self::MapperMismatch { expected, actual } => write!(
29 f,
30 "save state mapper mismatch: expected mapper {}, got mapper {}",
31 expected, actual
32 ),
33 Self::InvalidData(message) => f.write_str(message),
34 }
35 }
36}
37
38impl Error for SaveStateError {}
39
40pub(crate) struct StateWriter {
41 bytes: Vec<u8>,
42}
43
44impl StateWriter {
45 pub(crate) fn new() -> Self {
46 let mut writer = Self { bytes: Vec::new() };
47 writer.write_bytes(SAVE_STATE_MAGIC);
48 writer.write_u32(SAVE_STATE_VERSION);
49 writer
50 }
51
52 pub(crate) fn finish(self) -> Vec<u8> {
53 self.bytes
54 }
55
56 pub(crate) fn write_u8(&mut self, value: u8) {
57 self.bytes.push(value);
58 }
59
60 pub(crate) fn write_bool(&mut self, value: bool) {
61 self.write_u8(u8::from(value));
62 }
63
64 pub(crate) fn write_u16(&mut self, value: u16) {
65 self.bytes.extend_from_slice(&value.to_le_bytes());
66 }
67
68 pub(crate) fn write_u32(&mut self, value: u32) {
69 self.bytes.extend_from_slice(&value.to_le_bytes());
70 }
71
72 pub(crate) fn write_u64(&mut self, value: u64) {
73 self.bytes.extend_from_slice(&value.to_le_bytes());
74 }
75
76 pub(crate) fn write_i16(&mut self, value: i16) {
77 self.bytes.extend_from_slice(&value.to_le_bytes());
78 }
79
80 pub(crate) fn write_bytes(&mut self, bytes: &[u8]) {
81 self.bytes.extend_from_slice(bytes);
82 }
83}
84
85pub(crate) struct StateReader<'a> {
86 bytes: &'a [u8],
87 offset: usize,
88}
89
90impl<'a> StateReader<'a> {
91 pub(crate) fn new(bytes: &'a [u8]) -> Result<Self, SaveStateError> {
92 let mut reader = Self { bytes, offset: 0 };
93 let mut magic = [0; SAVE_STATE_MAGIC.len()];
94 reader.read_exact(&mut magic)?;
95 if &magic != SAVE_STATE_MAGIC {
96 return Err(SaveStateError::InvalidMagic);
97 }
98
99 let version = reader.read_u32()?;
100 if version != SAVE_STATE_VERSION {
101 return Err(SaveStateError::UnsupportedVersion(version));
102 }
103
104 Ok(reader)
105 }
106
107 pub(crate) fn finish(self) -> Result<(), SaveStateError> {
108 if self.offset == self.bytes.len() {
109 Ok(())
110 } else {
111 Err(SaveStateError::TrailingData)
112 }
113 }
114
115 pub(crate) fn read_u8(&mut self) -> Result<u8, SaveStateError> {
116 let mut buf = [0];
117 self.read_exact(&mut buf)?;
118 Ok(buf[0])
119 }
120
121 pub(crate) fn read_bool(&mut self) -> Result<bool, SaveStateError> {
122 match self.read_u8()? {
123 0 => Ok(false),
124 1 => Ok(true),
125 _ => Err(SaveStateError::InvalidData("boolean field must be 0 or 1")),
126 }
127 }
128
129 pub(crate) fn read_u16(&mut self) -> Result<u16, SaveStateError> {
130 let mut buf = [0; 2];
131 self.read_exact(&mut buf)?;
132 Ok(u16::from_le_bytes(buf))
133 }
134
135 pub(crate) fn read_u32(&mut self) -> Result<u32, SaveStateError> {
136 let mut buf = [0; 4];
137 self.read_exact(&mut buf)?;
138 Ok(u32::from_le_bytes(buf))
139 }
140
141 pub(crate) fn read_u64(&mut self) -> Result<u64, SaveStateError> {
142 let mut buf = [0; 8];
143 self.read_exact(&mut buf)?;
144 Ok(u64::from_le_bytes(buf))
145 }
146
147 pub(crate) fn read_i16(&mut self) -> Result<i16, SaveStateError> {
148 let mut buf = [0; 2];
149 self.read_exact(&mut buf)?;
150 Ok(i16::from_le_bytes(buf))
151 }
152
153 pub(crate) fn read_bytes_into(&mut self, bytes: &mut [u8]) -> Result<(), SaveStateError> {
154 self.read_exact(bytes)
155 }
156
157 fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), SaveStateError> {
158 let end = self.offset.saturating_add(buf.len());
159 if end > self.bytes.len() {
160 return Err(SaveStateError::UnexpectedEof);
161 }
162 buf.copy_from_slice(&self.bytes[self.offset..end]);
163 self.offset = end;
164 Ok(())
165 }
166}