spectrusty/memory/multi_page/
serde.rs1use core::convert::TryFrom;
9use serde::{Serialize, Deserialize};
10use serde::ser::{self, Serializer, SerializeStruct};
11use serde::de::{self, Deserializer};
12use super::super::arrays;
13use super::{
14 ExRom, MemoryConfig, MemoryBox, MemoryPages, MemPageableRomRamExRom, MemSerExt,
15 cast_slice_as_bank_ptr,
16 ro_flag_mask, serialize_mem, deserialize_mem};
17
18impl<const MEM_SIZE: usize, const PAGE_SIZE: usize, const NUM_PAGES: usize
19 > Serialize for MemPageableRomRamExRom<MEM_SIZE, PAGE_SIZE, NUM_PAGES>
20 where Self: MemoryConfig
21{
22 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
23
24 #[derive(Serialize)]
25 #[serde(transparent)]
26 struct MemSerWrap<'a, M>(
27 #[serde(serialize_with = "serialize_mem")] &'a M
28 ) where &'a M: MemSerExt;
29
30 #[derive(Serialize)]
31 #[serde(transparent)]
32 struct BanksWrap<const NUM_PAGES: usize>(
33 #[serde(with = "arrays")]
34 [u8; NUM_PAGES]
35 );
36
37 let mut pages = self.pages;
38 if let Some(exrom) = &self.ex_rom {
39 *pages.page_mut(exrom.page) = exrom.ptr;
40 }
41 let mem_ptr: *const u8 = self.mem.as_ptr();
42 let mut banks = BanksWrap([0u8; NUM_PAGES]);
43 for (p, b) in pages.0.iter().zip(banks.0.iter_mut()) {
44 let offset = unsafe { (p.as_ptr() as *const u8).offset_from(mem_ptr) };
45 assert_eq!(offset % PAGE_SIZE as isize, 0);
46 *b = u8::try_from(offset / PAGE_SIZE as isize)
47 .map_err(|err| ser::Error::custom(err.to_string()))?;
48 }
49 let mut state = serializer.serialize_struct("MemPageableRomRamExRom", 3)?;
50 state.serialize_field("mem", &MemSerWrap(&self.mem))?;
51 state.serialize_field("pages", &banks)?;
52 state.serialize_field("exrom", &self.ex_rom)?;
53 state.end()
54 }
55}
56
57impl<'de,
58 const MEM_SIZE: usize, const PAGE_SIZE: usize, const NUM_PAGES: usize
59 > Deserialize<'de> for MemPageableRomRamExRom<MEM_SIZE, PAGE_SIZE, NUM_PAGES>
60 where Self: MemoryConfig
61{
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where D: Deserializer<'de>
64 {
65 #[derive(Deserialize)]
66 struct MemTemp<const MEM_SIZE: usize, const NUM_PAGES: usize> {
67 #[serde(deserialize_with = "deserialize_mem")]
68 mem: MemoryBox<MEM_SIZE>,
69 #[serde(with = "arrays",rename(deserialize = "pages"))]
70 banks: [u8;NUM_PAGES],
71 exrom: Option<ExRomTemp>
72 }
73
74 #[derive(Deserialize)]
75 struct ExRomTemp {
76 page: u8,
77 #[serde(deserialize_with = "deserialize_mem")]
78 rom: ExRom
79 }
80
81 let MemTemp::<MEM_SIZE, NUM_PAGES> { mem, banks, exrom } = Deserialize::deserialize(deserializer)?;
82
83 let mut pages = MemoryPages::<PAGE_SIZE, NUM_PAGES>::new();
84 let mut ro_pages = 0;
85 let offset_max = mem.len() - PAGE_SIZE;
86 for ((p, bank), page) in pages.0.iter_mut().zip(banks).zip(0u8..) {
87 let offset = bank as usize * PAGE_SIZE;
88 if offset > offset_max {
89 return Err(de::Error::custom(format!("memory bank: {} larger than max: {}",
90 bank, offset_max / PAGE_SIZE)));
91 }
92 if (bank as usize) < Self::ROM_BANKS {
93 ro_pages |= ro_flag_mask(page);
94 }
95 *p = cast_slice_as_bank_ptr(&mem[offset..offset + PAGE_SIZE]);
96 }
97
98 let mut res = MemPageableRomRamExRom { mem, pages, ro_pages, ex_rom: None};
99 if let Some(ExRomTemp { page, rom }) = exrom {
100 if rom.len() != PAGE_SIZE {
101 return Err(de::Error::custom(format!("attached ex-rom size incorrect: {} != {}",
102 rom.len(), PAGE_SIZE)));
103 }
104 if page > Self::PAGES_MASK {
105 return Err(de::Error::custom(format!("attached ex-rom page: {} larger than max: {}",
106 page, Self::PAGES_MASK)));
107 }
108 res.attach_exrom(rom, page);
109 }
110 Ok(res)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use std::rc::Rc;
117 use crate::memory::multi_page::MEM16K_SIZE;
118 use crate::memory::*;
119 use core::ptr::NonNull;
120
121 fn page_mem_offset(mem: &[u8], ptr: NonNull<[u8; MEM16K_SIZE]>) -> usize {
122 let mem_ptr = mem.as_ptr() as usize;
123 ptr.as_ptr() as usize - mem_ptr
124 }
125
126 fn serde_compare(mem: &Memory128k, mem_de: &Memory128k, must_have_exrom: bool) {
127 for (a, b) in mem.mem.iter().zip(mem_de.mem.iter()) {
128 assert_eq!(*a, *b);
129 }
130 let mut pages = mem.pages;
131 let mut pages_de = mem_de.pages;
132 if let Some(ex_rom) = &mem.ex_rom {
133 *pages.page_mut(ex_rom.page) = ex_rom.ptr;
134 }
135 if let Some(ex_rom) = &mem_de.ex_rom {
136 *pages_de.page_mut(ex_rom.page) = ex_rom.ptr;
137 }
138 for (&a, &b) in pages.0.iter().zip(pages_de.0.iter()) {
139 page_mem_offset(&mem.mem_ref(), a);
140 page_mem_offset(&mem_de.mem_ref(), b);
141 }
142 assert_eq!(mem.ro_pages, mem_de.ro_pages);
143 if must_have_exrom {
144 assert!(mem.ex_rom.is_some());
145 assert!(mem_de.ex_rom.is_some());
146 assert_eq!(mem.ex_rom.as_ref().unwrap().page, mem_de.ex_rom.as_ref().unwrap().page);
147 assert_eq!(mem.ex_rom.as_ref().unwrap().ro, mem_de.ex_rom.as_ref().unwrap().ro);
148 assert_eq!(
149 page_mem_offset(&mem.ex_rom.as_ref().unwrap().rom[..], mem.pages.page(mem.ex_rom.as_ref().unwrap().page)),
150 page_mem_offset(&mem_de.ex_rom.as_ref().unwrap().rom[..], mem_de.pages.page(mem_de.ex_rom.as_ref().unwrap().page))
151 );
152 }
153 else {
154 assert!(mem.ex_rom.is_none());
155 assert!(mem_de.ex_rom.is_none());
156 }
157 }
158
159 #[test]
160 fn memory_serde_works() {
161 let mut mem = Memory128k::default();
162 let sermem = serde_json::to_string(&mem).unwrap();
163 let mem_de: Memory128k = serde_json::from_str(&sermem).unwrap();
164 serde_compare(&mem, &mem_de, false);
165
166 let encoded: Vec<u8> = bincode::serialize(&mem).unwrap();
167 let mem_de: Memory128k = bincode::deserialize(&encoded).unwrap();
168 serde_compare(&mem, &mem_de, false);
169
170 let exrom: Rc<[u8]> = Rc::from(vec![0u8;Memory128k::PAGE_SIZE]);
171 mem.map_exrom(Rc::clone(&exrom), 3).unwrap();
172 let sermem = serde_json::to_string(&mem).unwrap();
173 let mem_de: Memory128k = serde_json::from_str(&sermem).unwrap();
174 serde_compare(&mem, &mem_de, true);
175
176 let encoded: Vec<u8> = bincode::serialize(&mem).unwrap();
177 let mem_de: Memory128k = bincode::deserialize(&encoded).unwrap();
178 serde_compare(&mem, &mem_de, true);
179 }
180}