1#![allow(non_camel_case_types)]
2
3use libloading::Symbol;
4pub type Library = libloading::Library;
5pub mod sys;
6
7pub struct Core {
8 pub lib: Library,
9}
10
11macro_rules! forward_to_lib {
12 ($name:ident, fn($($arg:ident: $type:ty),*) $(-> $ret:ty)?) => {
13 pub extern "C" fn $name(&self, $($arg: $type),*) $(-> $ret)? {
14 unsafe {
15 let lib = &self.lib;
16 let func: Symbol<unsafe extern "C" fn($($type),*) $(-> $ret)?> = lib
17 .get(concat!(stringify!($name), "\0").as_bytes())
18 .expect(&format!("Failed to find function '{}' in proxied core", stringify!($name)));
19 func($($arg),*)
20 }
21 }
22 };
23}
24
25impl Core {
26 pub fn load(path: &str) -> Option<Core> {
27 unsafe {
28 Library::new(&path).ok().map(|lib| Core {lib})
29 }
30 }
31
32 forward_to_lib!(retro_set_environment, fn(cb: sys::retro_environment_t));
33 forward_to_lib!(retro_set_video_refresh, fn(cb: sys::retro_video_refresh_t));
34 forward_to_lib!(retro_set_audio_sample, fn(cb: sys::retro_audio_sample_t));
35 forward_to_lib!(retro_set_audio_sample_batch, fn(cb: sys::retro_audio_sample_batch_t));
36 forward_to_lib!(retro_set_input_poll, fn(cb: sys::retro_input_poll_t));
37 forward_to_lib!(retro_set_input_state, fn(cb: sys::retro_input_state_t));
38 forward_to_lib!(retro_init, fn());
39 forward_to_lib!(retro_deinit, fn());
40 forward_to_lib!(retro_api_version, fn() -> sys::c_uint);
41 forward_to_lib!(retro_get_system_info, fn(info: *mut sys::retro_system_info));
42 forward_to_lib!(retro_get_system_av_info, fn(info: *mut sys::retro_system_av_info));
43 forward_to_lib!(retro_set_controller_port_device, fn(port: sys::c_uint, device: sys::c_uint));
44 forward_to_lib!(retro_reset, fn());
45 forward_to_lib!(retro_run, fn());
46 forward_to_lib!(retro_serialize_size, fn() -> usize);
47 forward_to_lib!(retro_serialize, fn(data: *mut sys::c_void, size: usize) -> bool);
48 forward_to_lib!(retro_unserialize, fn(data: *const sys::c_void, size: usize) -> bool);
49 forward_to_lib!(retro_cheat_reset, fn());
50 forward_to_lib!(retro_cheat_set, fn(index: sys::c_uint, enabled: bool, code: *const sys::c_char));
51 forward_to_lib!(retro_load_game, fn(game: *const sys::retro_game_info) -> bool);
52 forward_to_lib!(retro_load_game_special, fn(game_type: sys::c_uint, info: *const sys::retro_game_info, num_info: usize) -> bool);
53 forward_to_lib!(retro_unload_game, fn());
54 forward_to_lib!(retro_get_region, fn() -> sys::c_uint);
55 forward_to_lib!(retro_get_memory_data, fn(id: sys::c_uint) -> *mut sys::c_void);
56 forward_to_lib!(retro_get_memory_size, fn(id: sys::c_uint) -> usize);
57}
58
59pub trait Proxy {
60 fn core(&self) -> &Core;
61
62 fn retro_set_environment(&self, cb: sys::retro_environment_t) { self.core().retro_set_environment(cb) }
63 fn retro_set_video_refresh(&self, cb: sys::retro_video_refresh_t) { self.core().retro_set_video_refresh(cb) }
64 fn retro_set_audio_sample(&self, cb: sys::retro_audio_sample_t) { self.core().retro_set_audio_sample(cb) }
65 fn retro_set_audio_sample_batch(&self, cb: sys::retro_audio_sample_batch_t) { self.core().retro_set_audio_sample_batch(cb) }
66 fn retro_set_input_poll(&self, cb: sys::retro_input_poll_t) { self.core().retro_set_input_poll(cb) }
67 fn retro_set_input_state(&self, cb: sys::retro_input_state_t) { self.core().retro_set_input_state(cb) }
68 fn retro_init(&self) { self.core().retro_init() }
69 fn retro_deinit(&self) { self.core().retro_deinit() }
70 fn retro_api_version(&self) -> sys::c_uint { self.core().retro_api_version() }
71 fn retro_get_system_info(&self, info: *mut sys::retro_system_info) { self.core().retro_get_system_info(info) }
72 fn retro_get_system_av_info(&self, info: *mut sys::retro_system_av_info) { self.core().retro_get_system_av_info(info) }
73 fn retro_set_controller_port_device(&self, port: sys::c_uint, device: sys::c_uint) { self.core().retro_set_controller_port_device(port, device) }
74 fn retro_reset(&self) { self.core().retro_reset() }
75 fn retro_run(&self) { self.core().retro_run() }
76 fn retro_serialize_size(&self) -> usize { self.core().retro_serialize_size() }
77 fn retro_serialize(&self, data: *mut sys::c_void, size: usize) -> bool { self.core().retro_serialize(data, size) }
78 fn retro_unserialize(&self, data: *const sys::c_void, size: usize) -> bool { self.core().retro_unserialize(data, size) }
79 fn retro_cheat_reset(&self) { self.core().retro_cheat_reset() }
80 fn retro_cheat_set(&self, index: sys::c_uint, enabled: bool, code: *const sys::c_char) { self.core().retro_cheat_set(index, enabled, code) }
81 fn retro_load_game(&self, game: *const sys::retro_game_info) -> bool { self.core().retro_load_game(game) }
82 fn retro_load_game_special(&self, game_type: sys::c_uint, info: *const sys::retro_game_info, num_info: usize) -> bool { self.core().retro_load_game_special(game_type, info, num_info) }
83 fn retro_unload_game(&self) { self.core().retro_unload_game() }
84 fn retro_get_region(&self) -> sys::c_uint { self.core().retro_get_region() }
85 fn retro_get_memory_data(&self, id: sys::c_uint) -> *mut sys::c_void { self.core().retro_get_memory_data(id) }
86 fn retro_get_memory_size(&self, id: sys::c_uint) -> usize { self.core().retro_get_memory_size(id) }
87}
88
89#[macro_export]
90macro_rules! proxy_to {
91 ($proxy:expr) => {
92 #[no_mangle] pub extern "C" fn retro_set_environment(cb: libretro_proxy::sys::retro_environment_t) { $proxy.retro_set_environment(cb) }
93 #[no_mangle] pub extern "C" fn retro_set_video_refresh(cb: libretro_proxy::sys::retro_video_refresh_t) { $proxy.retro_set_video_refresh(cb) }
94 #[no_mangle] pub extern "C" fn retro_set_audio_sample(cb: libretro_proxy::sys::retro_audio_sample_t) { $proxy.retro_set_audio_sample(cb) }
95 #[no_mangle] pub extern "C" fn retro_set_audio_sample_batch(cb: libretro_proxy::sys::retro_audio_sample_batch_t) { $proxy.retro_set_audio_sample_batch(cb) }
96 #[no_mangle] pub extern "C" fn retro_set_input_poll(cb: libretro_proxy::sys::retro_input_poll_t) { $proxy.retro_set_input_poll(cb) }
97 #[no_mangle] pub extern "C" fn retro_set_input_state(cb: libretro_proxy::sys::retro_input_state_t) { $proxy.retro_set_input_state(cb) }
98 #[no_mangle] pub extern "C" fn retro_init() { $proxy.retro_init() }
99 #[no_mangle] pub extern "C" fn retro_deinit() { $proxy.retro_deinit() }
100 #[no_mangle] pub extern "C" fn retro_api_version() -> libretro_proxy::sys::c_uint { $proxy.retro_api_version() }
101 #[no_mangle] pub extern "C" fn retro_get_system_info(info: *mut libretro_proxy::sys::retro_system_info) { $proxy.retro_get_system_info(info) }
102 #[no_mangle] pub extern "C" fn retro_get_system_av_info(info: *mut libretro_proxy::sys::retro_system_av_info) { $proxy.retro_get_system_av_info(info) }
103 #[no_mangle] pub extern "C" fn retro_set_controller_port_device(port: libretro_proxy::sys::c_uint, device: libretro_proxy::sys::c_uint) { $proxy.retro_set_controller_port_device(port, device) }
104 #[no_mangle] pub extern "C" fn retro_reset() { $proxy.retro_reset() }
105 #[no_mangle] pub extern "C" fn retro_run() { $proxy.retro_run() }
106 #[no_mangle] pub extern "C" fn retro_serialize_size() -> usize { $proxy.retro_serialize_size() }
107 #[no_mangle] pub extern "C" fn retro_serialize(data: *mut libretro_proxy::sys::c_void, size: usize) -> bool { $proxy.retro_serialize(data, size) }
108 #[no_mangle] pub extern "C" fn retro_unserialize(data: *const libretro_proxy::sys::c_void, size: usize) -> bool { $proxy.retro_unserialize(data, size) }
109 #[no_mangle] pub extern "C" fn retro_cheat_reset() { $proxy.retro_cheat_reset() }
110 #[no_mangle] pub extern "C" fn retro_cheat_set(index: libretro_proxy::sys::c_uint, enabled: bool, code: *const libretro_proxy::sys::c_char) { $proxy.retro_cheat_set(index, enabled, code) }
111 #[no_mangle] pub extern "C" fn retro_load_game(game: *const libretro_proxy::sys::retro_game_info) -> bool { $proxy.retro_load_game(game) }
112 #[no_mangle] pub extern "C" fn retro_load_game_special(game_type: libretro_proxy::sys::c_uint, info: *const libretro_proxy::sys::retro_game_info, num_info: usize) -> bool { $proxy.retro_load_game_special(game_type, info, num_info) }
113 #[no_mangle] pub extern "C" fn retro_unload_game() { $proxy.retro_unload_game() }
114 #[no_mangle] pub extern "C" fn retro_get_region() -> libretro_proxy::sys::c_uint { $proxy.retro_get_region() }
115 #[no_mangle] pub extern "C" fn retro_get_memory_data(id: libretro_proxy::sys::c_uint) -> *mut libretro_proxy::sys::c_void { $proxy.retro_get_memory_data(id) }
116 #[no_mangle] pub extern "C" fn retro_get_memory_size(id: libretro_proxy::sys::c_uint) -> usize { $proxy.retro_get_memory_size(id) }
117 };
118}