libretro_proxy/
lib.rs

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}