1use std::any::Any;
2use std::cell::UnsafeCell;
3use std::io::{Read, Seek, Write};
4use std::rc::Rc;
5use std::time::SystemTime;
6
7pub use bios::Bios;
8use image::DynamicImage;
9pub use null::NullCore;
10pub use rom::Rom;
11use serde::Serialize;
12
13use crate::inputs::{gamepad, keyboard};
14
15pub mod bios;
16pub mod null;
17pub mod rom;
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22pub struct SettingId(u32);
23
24impl Serialize for SettingId {
25 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
26 self.0.serialize(serializer)
27 }
28}
29
30impl From<u32> for SettingId {
31 fn from(value: u32) -> Self {
32 Self(value)
33 }
34}
35
36impl From<SettingId> for u32 {
37 fn from(value: SettingId) -> Self {
38 value.0
39 }
40}
41
42impl From<&str> for SettingId {
43 fn from(value: &str) -> Self {
44 Self::from_label(value)
45 }
46}
47
48impl From<&String> for SettingId {
49 fn from(value: &String) -> Self {
50 Self::from_label(value)
51 }
52}
53
54impl SettingId {
55 pub fn new(id: u32) -> Self {
56 Self(id)
57 }
58
59 pub fn from_label(label: &str) -> Self {
60 let mut s: u32 = 0;
61 for c in label.as_bytes() {
62 s = s.wrapping_mul(223).wrapping_add(*c as u32);
63 }
64 Self(s)
65 }
66
67 pub fn as_u32(&self) -> u32 {
68 self.0
69 }
70}
71
72#[derive(Debug, Serialize)]
76pub struct CoreSettings {
77 title: String,
78 items: Vec<CoreSettingItem>,
79}
80
81impl CoreSettings {
82 pub fn new(title: String, items: Vec<CoreSettingItem>) -> Self {
83 Self { title, items }
84 }
85
86 pub fn items(&self) -> &[CoreSettingItem] {
87 &self.items
88 }
89}
90
91#[derive(Debug, Serialize)]
97#[serde(rename_all = "camelCase", tag = "kind")]
98pub enum CoreSettingItem {
99 Page {
101 id: SettingId,
103
104 label: String,
106
107 title: String,
109
110 items: Vec<CoreSettingItem>,
112
113 disabled: bool,
115 },
116
117 Separator,
119
120 Label {
123 selectable: bool,
124 label: String,
125 disabled: bool,
126 },
127
128 #[serde(rename = "file")]
131 FileSelect {
132 id: SettingId,
133 label: String,
134 extensions: Vec<String>,
135 disabled: bool,
136 },
137
138 Trigger {
140 id: SettingId,
141 label: String,
142 disabled: bool,
143 },
144
145 #[serde(rename = "bool")]
148 BoolOption {
149 id: SettingId,
150 label: String,
151 value: bool,
152 disabled: bool,
153 },
154
155 #[serde(rename = "int")]
162 IntOption {
163 id: SettingId,
164 label: String,
165 choices: Vec<String>,
166 value: usize,
167 disabled: bool,
168 },
169}
170
171impl CoreSettingItem {
172 pub fn with_disabled(mut self, disabled: bool) -> Self {
173 self.set_disable(disabled);
174 self
175 }
176
177 pub fn set_disable(&mut self, new_disabled: bool) {
178 match self {
179 CoreSettingItem::Page { disabled, .. }
180 | CoreSettingItem::Label { disabled, .. }
181 | CoreSettingItem::Trigger { disabled, .. }
182 | CoreSettingItem::FileSelect { disabled, .. }
183 | CoreSettingItem::BoolOption { disabled, .. }
184 | CoreSettingItem::IntOption { disabled, .. } => {
185 *disabled = new_disabled;
186 }
187 _ => {}
188 }
189 }
190
191 pub fn page(
192 id: impl Into<SettingId>,
193 label: &str,
194 title: &str,
195 items: Vec<CoreSettingItem>,
196 ) -> Self {
197 CoreSettingItem::Page {
198 id: id.into(),
199 label: label.to_string(),
200 title: title.to_string(),
201 items,
202 disabled: false,
203 }
204 }
205
206 pub fn items(&self) -> Option<&Vec<CoreSettingItem>> {
207 match self {
208 CoreSettingItem::Page { items, .. } => Some(items),
209 _ => None,
210 }
211 }
212
213 pub fn items_mut(&mut self) -> Option<&mut Vec<CoreSettingItem>> {
214 match self {
215 CoreSettingItem::Page { items, .. } => Some(items),
216 _ => None,
217 }
218 }
219
220 pub fn separator() -> Self {
221 CoreSettingItem::Separator
222 }
223
224 pub fn label(selectable: bool, label: &str) -> Self {
225 CoreSettingItem::Label {
226 selectable,
227 label: label.to_string(),
228 disabled: false,
229 }
230 }
231
232 pub fn file_select(id: impl Into<SettingId>, label: &str, extensions: Vec<String>) -> Self {
233 CoreSettingItem::FileSelect {
234 id: id.into(),
235 label: label.to_string(),
236 extensions,
237 disabled: false,
238 }
239 }
240
241 pub fn trigger(id: impl Into<SettingId>, label: &str) -> Self {
242 CoreSettingItem::Trigger {
243 id: id.into(),
244 label: label.to_string(),
245 disabled: false,
246 }
247 }
248
249 pub fn bool_option(id: impl Into<SettingId>, label: &str, value: Option<bool>) -> Self {
250 CoreSettingItem::BoolOption {
251 id: id.into(),
252 label: label.to_string(),
253 value: value.unwrap_or_default(),
254 disabled: false,
255 }
256 }
257
258 pub fn int_option(
259 id: impl Into<SettingId>,
260 label: &str,
261 choices: Vec<String>,
262 value: Option<usize>,
263 ) -> Self {
264 CoreSettingItem::IntOption {
265 id: id.into(),
266 label: label.to_string(),
267 choices,
268 value: value.unwrap_or_default(),
269 disabled: false,
270 }
271 }
272
273 pub fn add_item(&mut self, sub: CoreSettingItem) {
274 if let CoreSettingItem::Page { items, .. } = self {
275 items.push(sub);
276 }
277 }
278}
279
280pub trait SaveState {
283 fn is_dirty(&self) -> bool;
285
286 fn save(&mut self, writer: &mut dyn Write) -> Result<(), Error>;
288
289 fn load(&mut self, reader: &mut dyn Read) -> Result<(), Error>;
291}
292
293pub trait MountedFile: Read + Write + Seek {}
296
297#[derive(Debug, thiserror::Error)]
299pub enum Error {
300 #[error("An error occurred: {0}")]
301 Generic(String),
302
303 #[error("An error occurred: {0}")]
304 IoError(#[from] std::io::Error),
305
306 #[error("An error occurred: {0}")]
307 Message(String),
308
309 #[error("An error occurred: {0}")]
310 AnyError(#[from] Box<dyn std::error::Error>),
311}
312
313impl From<String> for Error {
314 fn from(value: String) -> Self {
315 Error::Generic(value)
316 }
317}
318
319#[derive(Copy, Clone)]
321pub struct SaveStateIter<'a, T: Core> {
322 core: &'a T,
323 valid: bool,
324 index: usize,
325}
326
327impl<'a, T: Core> SaveStateIter<'a, T> {
328 pub fn new(core: &'a T) -> Self {
329 Self {
330 core,
331 valid: true,
332 index: 0,
333 }
334 }
335}
336
337impl<'a, T: Core> Iterator for SaveStateIter<'a, T> {
338 type Item = &'a dyn SaveState;
339
340 fn next(&mut self) -> Option<Self::Item> {
341 if !self.valid {
342 return None;
343 }
344
345 match self.core.save_state(self.index) {
346 Ok(Some(state)) => {
347 self.index += 1;
348 Some(state)
349 }
350 Ok(None) => None,
351 Err(_e) => {
352 self.valid = false;
353 None
354 }
355 }
356 }
357}
358
359pub trait Core {
360 fn init(&mut self) -> Result<(), Error>;
362
363 fn name(&self) -> &str;
365
366 fn reset(&mut self) -> Result<(), Error>;
368
369 fn set_volume(&mut self, volume: u8) -> Result<(), Error>;
373
374 fn set_rtc(&mut self, time: SystemTime) -> Result<(), Error>;
376
377 fn screenshot(&self) -> Result<DynamicImage, Error>;
379
380 fn save_state_mut(&mut self, slot: usize) -> Result<Option<&mut dyn SaveState>, Error>;
385
386 fn save_state(&self, slot: usize) -> Result<Option<&dyn SaveState>, Error>;
391
392 fn mounted_file_mut(&mut self, slot: usize) -> Result<Option<&mut dyn MountedFile>, Error>;
397
398 fn send_rom(&mut self, rom: Rom) -> Result<(), Error>;
400
401 fn send_bios(&mut self, bios: Bios) -> Result<(), Error>;
405
406 fn key_up(&mut self, key: keyboard::Scancode) -> Result<(), Error>;
408
409 fn key_down(&mut self, key: keyboard::Scancode) -> Result<(), Error>;
411
412 fn keys_set(&mut self, keys: keyboard::ScancodeSet) -> Result<(), Error>;
415
416 fn keys(&self) -> Result<keyboard::ScancodeSet, Error>;
419
420 fn gamepad_button_up(&mut self, index: usize, button: gamepad::Button) -> Result<(), Error>;
421 fn gamepad_button_down(&mut self, index: usize, button: gamepad::Button) -> Result<(), Error>;
422 fn gamepad_buttons_set(
423 &mut self,
424 index: usize,
425 buttons: gamepad::ButtonSet,
426 ) -> Result<(), Error>;
427
428 fn gamepad_buttons(&self, index: usize) -> Result<Option<gamepad::ButtonSet>, Error>;
433
434 fn settings(&self) -> Result<CoreSettings, Error>;
438
439 fn trigger(&mut self, id: SettingId) -> Result<(), Error>;
442
443 fn file_select(&mut self, id: SettingId, path: String) -> Result<(), Error>;
445
446 fn int_option(&mut self, id: SettingId, value: u32) -> Result<u32, Error>;
450
451 fn bool_option(&mut self, id: SettingId, value: bool) -> Result<bool, Error>;
455
456 fn as_any(&self) -> &dyn Any;
457 fn as_any_mut(&mut self) -> &mut dyn Any;
458
459 fn quit(&mut self);
463
464 fn should_quit(&self) -> bool;
467}
468
469#[derive(Clone)]
478pub struct OneFpgaCore {
479 name: String,
480 inner: Rc<UnsafeCell<dyn Core + 'static>>,
481}
482
483impl OneFpgaCore {
484 pub fn new(core: impl Core + 'static) -> Self {
485 Self {
486 name: core.name().to_string(),
487 inner: Rc::new(UnsafeCell::new(core)),
488 }
489 }
490
491 pub fn null() -> Self {
492 Self::new(NullCore)
493 }
494}
495
496impl Core for OneFpgaCore {
497 fn init(&mut self) -> Result<(), Error> {
498 unsafe { &mut *self.inner.get() }.init()
499 }
500
501 fn name(&self) -> &str {
502 &self.name
503 }
504
505 fn reset(&mut self) -> Result<(), Error> {
506 unsafe { &mut *self.inner.get() }.reset()
507 }
508
509 fn set_volume(&mut self, volume: u8) -> Result<(), Error> {
510 unsafe { &mut *self.inner.get() }.set_volume(volume)
511 }
512
513 fn set_rtc(&mut self, time: SystemTime) -> Result<(), Error> {
514 unsafe { &mut *self.inner.get() }.set_rtc(time)
515 }
516
517 fn screenshot(&self) -> Result<DynamicImage, Error> {
518 unsafe { &mut *self.inner.get() }.screenshot()
519 }
520
521 fn save_state_mut(&mut self, slot: usize) -> Result<Option<&mut dyn SaveState>, Error> {
522 unsafe { &mut *self.inner.get() }.save_state_mut(slot)
523 }
524
525 fn save_state(&self, slot: usize) -> Result<Option<&dyn SaveState>, Error> {
526 unsafe { &mut *self.inner.get() }.save_state(slot)
527 }
528
529 fn mounted_file_mut(&mut self, slot: usize) -> Result<Option<&mut dyn MountedFile>, Error> {
530 unsafe { &mut *self.inner.get() }.mounted_file_mut(slot)
531 }
532
533 fn send_rom(&mut self, rom: Rom) -> Result<(), Error> {
534 unsafe { &mut *self.inner.get() }.send_rom(rom)
535 }
536
537 fn send_bios(&mut self, bios: Bios) -> Result<(), Error> {
538 unsafe { &mut *self.inner.get() }.send_bios(bios)
539 }
540
541 fn key_up(&mut self, key: keyboard::Scancode) -> Result<(), Error> {
542 unsafe { &mut *self.inner.get() }.key_up(key)
543 }
544
545 fn key_down(&mut self, key: keyboard::Scancode) -> Result<(), Error> {
546 unsafe { &mut *self.inner.get() }.key_down(key)
547 }
548
549 fn keys_set(&mut self, keys: keyboard::ScancodeSet) -> Result<(), Error> {
550 unsafe { &mut *self.inner.get() }.keys_set(keys)
551 }
552
553 fn keys(&self) -> Result<keyboard::ScancodeSet, Error> {
554 unsafe { &mut *self.inner.get() }.keys()
555 }
556
557 fn gamepad_button_up(&mut self, index: usize, button: gamepad::Button) -> Result<(), Error> {
558 unsafe { &mut *self.inner.get() }.gamepad_button_up(index, button)
559 }
560
561 fn gamepad_button_down(&mut self, index: usize, button: gamepad::Button) -> Result<(), Error> {
562 unsafe { &mut *self.inner.get() }.gamepad_button_down(index, button)
563 }
564
565 fn gamepad_buttons_set(
566 &mut self,
567 index: usize,
568 buttons: gamepad::ButtonSet,
569 ) -> Result<(), Error> {
570 unsafe { &mut *self.inner.get() }.gamepad_buttons_set(index, buttons)
571 }
572
573 fn gamepad_buttons(&self, index: usize) -> Result<Option<gamepad::ButtonSet>, Error> {
574 unsafe { &mut *self.inner.get() }.gamepad_buttons(index)
575 }
576
577 fn settings(&self) -> Result<CoreSettings, Error> {
578 unsafe { &mut *self.inner.get() }.settings()
579 }
580
581 fn trigger(&mut self, id: SettingId) -> Result<(), Error> {
582 unsafe { &mut *self.inner.get() }.trigger(id)
583 }
584
585 fn file_select(&mut self, id: SettingId, path: String) -> Result<(), Error> {
586 unsafe { &mut *self.inner.get() }.file_select(id, path)
587 }
588
589 fn int_option(&mut self, id: SettingId, value: u32) -> Result<u32, Error> {
590 unsafe { &mut *self.inner.get() }.int_option(id, value)
591 }
592
593 fn bool_option(&mut self, id: SettingId, value: bool) -> Result<bool, Error> {
594 unsafe { &mut *self.inner.get() }.bool_option(id, value)
595 }
596
597 fn as_any(&self) -> &dyn Any {
598 unsafe { &mut *self.inner.get() }.as_any()
599 }
600
601 fn as_any_mut(&mut self) -> &mut dyn Any {
602 unsafe { &mut *self.inner.get() }.as_any_mut()
603 }
604
605 fn quit(&mut self) {
606 unsafe { &mut *self.inner.get() }.quit();
607 }
608
609 fn should_quit(&self) -> bool {
610 unsafe { &*self.inner.get() }.should_quit()
611 }
612}