1#![allow(clippy::missing_safety_doc)]
2#![doc(
3 html_logo_url = "https://raw.githubusercontent.com/max-m/rust-libretro/master/media/logo.png",
4 html_favicon_url = "https://raw.githubusercontent.com/max-m/rust-libretro/master/media/favicon.png"
5)]
6
7#[cfg(feature = "log")]
8mod logger;
9
10mod core_wrapper;
11mod macros;
12
13pub mod contexts;
14pub mod core;
15pub mod environment;
16pub mod types;
17pub mod util;
18
19pub use const_str;
20pub use macros::*;
21pub use rust_libretro_proc as proc;
22pub use rust_libretro_sys as sys;
23
24use crate::{contexts::*, core::Core, core_wrapper::CoreWrapper, sys::*, types::*, util::*};
25use std::{
26 ffi::*,
27 os::raw::c_char,
28 path::{Path, PathBuf},
29 sync::Arc,
30};
31
32#[doc(hidden)]
33static mut RETRO_INSTANCE: Option<CoreWrapper> = None;
34
35#[macro_export]
89macro_rules! retro_core {
90 ( $( $definition:tt )+ ) => {
91 #[doc(hidden)]
92 #[inline(never)]
93 #[no_mangle]
94 pub unsafe extern "Rust" fn __retro_init_core() {
95 $crate::set_core($($definition)+);
96 }
97 }
98}
99
100#[doc(hidden)]
101macro_rules! forward {
102 ($(#[doc = $doc:tt ], )* $wrapper:ident, $name:ident, $handler:ident $(-> $return_type:ty)?, $($context:tt)+) => {
103 #[no_mangle]
104 $(#[doc = $doc])*
105 pub unsafe extern "C" fn $name() $(-> $return_type)? {
106 if let Some($wrapper) = RETRO_INSTANCE.as_mut() {
108 let mut ctx = $($context)+;
110 return $wrapper.core.$handler(&mut ctx);
111 }
112
113 panic!(concat!(stringify!($name), ": Core has not been initialized yet!"));
114 }
115 };
116}
117
118#[doc(hidden)]
119macro_rules! callback {
120 ($(#[doc = $doc:tt ], )* $name:ident, $arg:ident, $handler:ident) => {
121 #[no_mangle]
122 $(#[doc = $doc])*
123 pub unsafe extern "C" fn $name(arg1: $arg) {
124 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
126 if arg1.is_some() {
127 if (arg1.unwrap() as *const c_void).is_null() {
129 panic!(concat!(
130 "Expected ",
131 stringify!($arg),
132 " got NULL pointer instead!"
133 ));
134 }
135 }
136
137 return wrapper.$handler(arg1);
139 }
140
141 panic!(concat!(
142 stringify!($name),
143 ": Core has not been initialized yet!"
144 ));
145 }
146 };
147}
148
149#[doc(hidden)]
150pub fn set_core<C: 'static + Core>(core: C) {
151 unsafe {
152 if RETRO_INSTANCE.is_some() {
153 let core = &RETRO_INSTANCE.as_ref().unwrap().core;
154 let info = core.get_info();
155 let name = info.library_name.into_string().unwrap();
156 let version = info.library_version.into_string().unwrap();
157
158 panic!("Attempted to set a core after the system was already initialized.\nAlready registered core: {} {}", name, version)
159 }
160
161 RETRO_INSTANCE.replace(CoreWrapper::new(core));
162 }
163}
164
165#[cfg(feature = "log")]
166#[doc(hidden)]
167fn init_log(env_callback: retro_environment_t) {
168 let retro_logger = unsafe { environment::get_log_callback(env_callback) };
169
170 let retro_logger = if let Ok(Some(log_callback)) = retro_logger {
171 logger::RetroLogger::new(log_callback)
172 } else {
173 logger::RetroLogger::new(retro_log_callback { log: None })
174 };
175
176 log::set_max_level(log::LevelFilter::Trace);
177 log::set_boxed_logger(Box::new(retro_logger)).expect("could not set logger");
178}
179
180forward!(
185 #[doc = "Notifies the [`Core`] when all cheats should be unapplied."],
186 wrapper,
187 retro_cheat_reset,
188 on_cheat_reset,
189 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
190);
191forward!(
192 #[doc = "Notifies the [`Core`] when it is being closed and its resources should be freed."],
193 wrapper,
194 retro_deinit,
195 on_deinit,
196 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
197);
198forward!(
199 #[doc = "Called when the frontend needs region information from the [`Core`]."],
200 #[doc = ""],
201 #[doc = "## Note about RetroArch:"],
202 #[doc = "RetroArch doesn’t use this interface anymore, because [`retro_get_system_av_info`] provides similar information."],
203 wrapper,
204 retro_get_region,
205 on_get_region -> std::os::raw::c_uint,
206 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
207);
208forward!(
209 #[doc = "Notifies the [`Core`] when the current game should be reset."],
210 wrapper,
211 retro_reset,
212 on_reset,
213 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
214);
215forward!(
216 #[doc = "Called when the frontend needs to know how large a buffer to allocate for save states."],
217 #[doc = ""],
218 #[doc = "See also [`rust_libretro_sys::retro_serialize_size`]."],
219 wrapper,
220 retro_serialize_size,
221 get_serialize_size -> usize,
222 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
223);
224forward!(
225 #[doc = "Notifies the [`Core`] when the currently loaded game should be unloaded. Called before [`retro_deinit`]."],
226 wrapper,
227 retro_unload_game,
228 on_unload_game,
229 GenericContext::new(&wrapper.environment_callback, Arc::clone(&wrapper.interfaces))
230);
231
232callback!(
233 #[doc = "Provides the audio sample callback to the [`Core`]."],
234 #[doc = ""],
235 #[doc = "Guaranteed to have been called before the first call to [`retro_run`] is made."],
236 retro_set_audio_sample,
237 retro_audio_sample_t,
238 on_set_audio_sample
239);
240callback!(
241 #[doc = "Provides the batched audio sample callback to the [`Core`]."],
242 #[doc = ""],
243 #[doc = "Guaranteed to have been called before the first call to [`retro_run`] is made."],
244 retro_set_audio_sample_batch,
245 retro_audio_sample_batch_t,
246 on_set_audio_sample_batch
247);
248callback!(
249 #[doc = "Provides the input polling callback to the [`Core`]."],
250 #[doc = ""],
251 #[doc = "Guaranteed to have been called before the first call to [`retro_run`] is made."],
252 retro_set_input_poll,
253 retro_input_poll_t,
254 on_set_input_poll
255);
256callback!(
257 #[doc = "Provides the input state request callback to the [`Core`]."],
258 #[doc = ""],
259 #[doc = "Guaranteed to have been called before the first call to [`retro_run`] is made."],
260 retro_set_input_state,
261 retro_input_state_t,
262 on_set_input_state
263);
264callback!(
265 #[doc = "Provides the frame drawing callback to the [`Core`]."],
266 #[doc = ""],
267 #[doc = "Guaranteed to have been called before the first call to [`retro_run`] is made."],
268 retro_set_video_refresh,
269 retro_video_refresh_t,
270 on_set_video_refresh
271);
272
273#[no_mangle]
275pub unsafe extern "C" fn retro_api_version() -> std::os::raw::c_uint {
276 #[cfg(feature = "log")]
277 log::trace!("retro_api_version()");
278
279 RETRO_API_VERSION
280}
281
282#[no_mangle]
286pub unsafe extern "C" fn retro_init() {
287 #[cfg(feature = "log")]
288 log::trace!("retro_init()");
289
290 if let Some(mut wrapper) = RETRO_INSTANCE.as_mut() {
291 wrapper.can_dupe = environment::can_dupe(wrapper.environment_callback);
292
293 let mut ctx = InitContext::new(
294 &wrapper.environment_callback,
295 Arc::clone(&wrapper.interfaces),
296 );
297
298 return wrapper.core.on_init(&mut ctx);
299 }
300
301 panic!("retro_init: Core has not been initialized yet!");
302}
303
304#[no_mangle]
308pub unsafe extern "C" fn retro_get_system_info(info: *mut retro_system_info) {
309 #[cfg(feature = "log")]
310 log::trace!("retro_get_system_info(info = {info:#?})");
311
312 if info.is_null() {
314 panic!("Expected retro_system_info, got NULL pointer instead!");
315 }
316
317 let info = &mut *info;
319
320 static mut SYS_INFO: Option<*const SystemInfo> = None;
325
326 let sys_info = {
327 if SYS_INFO.is_none() {
328 extern "Rust" {
329 fn __retro_init_core();
330 }
331 __retro_init_core();
332
333 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
334 SYS_INFO = Some(Box::into_raw(Box::new(wrapper.core.get_info())));
335 } else {
336 panic!("No core instance found!");
337 }
338 }
339
340 &*SYS_INFO.unwrap()
341 };
342
343 info.library_name = sys_info.library_name.as_ptr();
344 info.library_version = sys_info.library_version.as_ptr();
345 info.valid_extensions = sys_info.valid_extensions.as_ptr();
346 info.need_fullpath = sys_info.need_fullpath;
347 info.block_extract = sys_info.block_extract;
348}
349
350#[no_mangle]
356pub unsafe extern "C" fn retro_get_system_av_info(info: *mut retro_system_av_info) {
357 #[cfg(feature = "log")]
358 log::trace!("retro_get_system_av_info(info = {info:#?})");
359
360 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
361 if info.is_null() {
363 panic!("Expected retro_system_av_info, got NULL pointer instead!");
364 }
365
366 let info = &mut *info;
368
369 let mut ctx = GetAvInfoContext::new(
370 &wrapper.environment_callback,
371 Arc::clone(&wrapper.interfaces),
372 );
373
374 let av_info = wrapper.core.on_get_av_info(&mut ctx);
375
376 info.geometry = av_info.geometry;
377 info.timing = av_info.timing;
378
379 return;
380 }
381
382 panic!("retro_get_system_av_info: Core has not been initialized yet!");
383}
384
385#[no_mangle]
391pub unsafe extern "C" fn retro_set_environment(environment: retro_environment_t) {
392 #[cfg(feature = "log")]
393 log::trace!("retro_set_environment(environment = {environment:#?})");
394
395 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
396 let mut initial = false;
397
398 if let Some(callback) = environment {
399 if !wrapper.environment_set {
400 initial = true;
401 wrapper.environment_set = true;
402
403 #[cfg(feature = "log")]
404 init_log(Some(callback));
405
406 #[cfg(feature = "unstable-env-commands")]
407 {
408 wrapper.supports_bitmasks = environment::get_input_bitmasks(Some(callback));
409 }
410 }
411
412 wrapper.environment_callback.replace(callback);
413 } else {
414 wrapper.environment_callback.take();
415 }
416
417 let mut ctx = SetEnvironmentContext::new(
418 &wrapper.environment_callback,
419 Arc::clone(&wrapper.interfaces),
420 );
421
422 if initial && !wrapper.core.set_core_options(&ctx) {
425 #[cfg(feature = "log")]
426 log::warn!("Failed to set core options");
427 }
428
429 return wrapper.core.on_set_environment(initial, &mut ctx);
430 }
431
432 panic!("retro_set_environment: Core has not been initialized yet!");
433}
434
435#[no_mangle]
439pub unsafe extern "C" fn retro_set_controller_port_device(
440 port: std::os::raw::c_uint,
441 device: std::os::raw::c_uint,
442) {
443 #[cfg(feature = "log")]
444 log::trace!("retro_set_controller_port_device(port = {port}, device = {device})");
445
446 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
447 let mut ctx = GenericContext::new(
448 &wrapper.environment_callback,
449 Arc::clone(&wrapper.interfaces),
450 );
451
452 return wrapper
453 .core
454 .on_set_controller_port_device(port, device, &mut ctx);
455 }
456
457 panic!("retro_set_controller_port_device: Core has not been initialized yet!");
458}
459
460#[no_mangle]
464pub unsafe extern "C" fn retro_run() {
465 #[cfg(feature = "log")]
466 log::trace!("retro_run()");
467
468 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
469 if environment::get_variable_update(wrapper.environment_callback) {
470 let mut ctx = OptionsChangedContext::new(
471 &wrapper.environment_callback,
472 Arc::clone(&wrapper.interfaces),
473 );
474
475 wrapper.core.on_options_changed(&mut ctx);
476 }
477
478 if let Some(callback) = wrapper.input_poll_callback {
479 (callback)();
480 }
481
482 let mut ctx = RunContext {
483 environment_callback: &wrapper.environment_callback,
484 interfaces: Arc::clone(&wrapper.interfaces),
485
486 video_refresh_callback: &wrapper.video_refresh_callback,
487 audio_sample_callback: &wrapper.audio_sample_callback,
488 audio_sample_batch_callback: &wrapper.audio_sample_batch_callback,
489 input_poll_callback: &wrapper.input_poll_callback,
490 input_state_callback: &wrapper.input_state_callback,
491
492 can_dupe: wrapper.can_dupe,
493 had_frame: &mut wrapper.had_frame,
494 last_width: &mut wrapper.last_width,
495 last_height: &mut wrapper.last_height,
496 last_pitch: &mut wrapper.last_pitch,
497
498 supports_bitmasks: wrapper.supports_bitmasks,
499 };
500
501 return wrapper.core.on_run(&mut ctx, wrapper.frame_delta.take());
502 }
503
504 panic!("retro_run: Core has not been initialized yet!");
505}
506
507#[no_mangle]
512pub unsafe extern "C" fn retro_serialize(data: *mut std::os::raw::c_void, size: usize) -> bool {
513 #[cfg(feature = "log")]
514 log::trace!("retro_serialize(data = {data:#?}, size = {size})");
515
516 if data.is_null() {
517 #[cfg(feature = "log")]
518 log::warn!("retro_serialize: data is null");
519
520 return false;
521 }
522
523 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
524 let mut ctx = GenericContext::new(
525 &wrapper.environment_callback,
526 Arc::clone(&wrapper.interfaces),
527 );
528
529 let slice = std::slice::from_raw_parts_mut(data as *mut u8, size);
531
532 return wrapper.core.on_serialize(slice, &mut ctx);
533 }
534
535 panic!("retro_serialize: Core has not been initialized yet!");
536}
537
538#[no_mangle]
543pub unsafe extern "C" fn retro_unserialize(data: *const std::os::raw::c_void, size: usize) -> bool {
544 #[cfg(feature = "log")]
545 log::trace!("retro_unserialize(data = {data:#?}, size = {size})");
546
547 if data.is_null() {
548 #[cfg(feature = "log")]
549 log::warn!("retro_unserialize: data is null");
550
551 return false;
552 }
553
554 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
555 let mut ctx = GenericContext::new(
556 &wrapper.environment_callback,
557 Arc::clone(&wrapper.interfaces),
558 );
559
560 let slice = std::slice::from_raw_parts_mut(data as *mut u8, size);
562
563 return wrapper.core.on_unserialize(slice, &mut ctx);
564 }
565
566 panic!("retro_unserialize: Core has not been initialized yet!");
567}
568
569#[no_mangle]
574pub unsafe extern "C" fn retro_cheat_set(
575 index: std::os::raw::c_uint,
576 enabled: bool,
577 code: *const std::os::raw::c_char,
578) {
579 #[cfg(feature = "log")]
580 log::trace!("retro_cheat_set(index = {index}, enabled = {enabled}, code = {code:#?})");
581
582 if code.is_null() {
583 #[cfg(feature = "log")]
584 log::warn!("retro_cheat_set: code is null");
585
586 return;
587 }
588
589 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
590 let mut ctx = GenericContext::new(
591 &wrapper.environment_callback,
592 Arc::clone(&wrapper.interfaces),
593 );
594
595 let code = CStr::from_ptr(code);
602
603 return wrapper.core.on_cheat_set(index, enabled, code, &mut ctx);
604 }
605
606 panic!("retro_cheat_set: Core has not been initialized yet!");
607}
608
609#[no_mangle]
613pub unsafe extern "C" fn retro_load_game(game: *const retro_game_info) -> bool {
614 #[cfg(feature = "log")]
615 log::trace!("retro_load_game(game_type = {game:#?})");
616
617 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
618 let mut ctx = OptionsChangedContext::new(
619 &wrapper.environment_callback,
620 Arc::clone(&wrapper.interfaces),
621 );
622
623 wrapper.core.on_options_changed(&mut ctx);
624
625 let mut ctx = LoadGameContext::new(
626 &wrapper.environment_callback,
627 Arc::clone(&wrapper.interfaces),
628 );
629
630 let status = if game.is_null() {
631 wrapper.core.on_load_game(None, &mut ctx)
632 } else {
633 wrapper.core.on_load_game(Some(*game), &mut ctx)
634 };
635
636 cfg_if::cfg_if! {
637 if #[cfg(feature = "log")] {
638 match status {
639 Ok(()) => return true,
640 Err(err) => {
641 log::error!("Failed to load game: {:?}", err);
642 return false;
643 }
644 }
645 }
646 else {
647 return status.is_ok();
648 }
649 }
650 }
651
652 panic!("retro_load_game: Core has not been initialized yet!");
653}
654
655#[no_mangle]
657pub unsafe extern "C" fn retro_load_game_special(
658 game_type: std::os::raw::c_uint,
659 info: *const retro_game_info,
660 num_info: usize,
661) -> bool {
662 #[cfg(feature = "log")]
663 log::trace!(
664 "retro_load_game_special(game_type = {game_type}, info = {info:#?}, num_info = {num_info})"
665 );
666
667 if info.is_null() {
668 #[cfg(feature = "log")]
669 log::warn!("retro_load_game_special: info is null");
670
671 return false;
672 }
673
674 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
675 let mut ctx = OptionsChangedContext::new(
676 &wrapper.environment_callback,
677 Arc::clone(&wrapper.interfaces),
678 );
679
680 wrapper.core.on_options_changed(&mut ctx);
681
682 let mut ctx = LoadGameSpecialContext::new(
683 &wrapper.environment_callback,
684 Arc::clone(&wrapper.interfaces),
685 );
686
687 let status = wrapper
688 .core
689 .on_load_game_special(game_type, info, num_info, &mut ctx);
690
691 cfg_if::cfg_if! {
692 if #[cfg(feature = "log")] {
693 match status {
694 Ok(()) => return true,
695 Err(err) => {
696 log::error!("Failed to load special game: {:?}", err);
697 return false;
698 }
699 }
700 }
701 else {
702 return status.is_ok();
703 }
704 }
705 }
706
707 panic!("retro_load_game_special: Core has not been initialized yet!");
708}
709
710#[no_mangle]
715pub unsafe extern "C" fn retro_get_memory_data(
716 id: std::os::raw::c_uint,
717) -> *mut std::os::raw::c_void {
718 #[cfg(feature = "log")]
719 log::trace!("retro_get_memory_data(id = {id})");
720
721 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
722 let mut ctx = GenericContext::new(
723 &wrapper.environment_callback,
724 Arc::clone(&wrapper.interfaces),
725 );
726
727 return wrapper.core.get_memory_data(id, &mut ctx);
728 }
729
730 panic!("retro_get_memory_data: Core has not been initialized yet!");
731}
732
733#[no_mangle]
738pub unsafe extern "C" fn retro_get_memory_size(id: std::os::raw::c_uint) -> usize {
739 #[cfg(feature = "log")]
740 log::trace!("retro_get_memory_size(id = {id})");
741
742 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
743 let mut ctx = GenericContext::new(
744 &wrapper.environment_callback,
745 Arc::clone(&wrapper.interfaces),
746 );
747
748 return wrapper.core.get_memory_size(id, &mut ctx);
749 }
750
751 panic!("retro_get_memory_size: Core has not been initialized yet!");
752}
753
754#[no_mangle]
766pub unsafe extern "C" fn retro_keyboard_callback_fn(
767 down: bool,
768 keycode: ::std::os::raw::c_uint,
769 character: u32,
770 key_modifiers: u16,
771) {
772 #[cfg(feature = "log")]
773 log::trace!("retro_keyboard_callback_fn(down = {down}, keycode = {keycode}, character = {character}, key_modifiers = {key_modifiers})");
774
775 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
776 cfg_if::cfg_if! {
779 if #[cfg(target_family = "windows")] {
780 let keycode = keycode as i32;
781 }
782 };
783
784 return wrapper.core.on_keyboard_event(
785 down,
786 retro_key(keycode),
787 character,
788 retro_mod(key_modifiers.into()),
789 );
790 }
791
792 panic!("retro_keyboard_callback_fn: Core has not been initialized yet!");
793}
794
795#[no_mangle]
797pub unsafe extern "C" fn retro_hw_context_reset_callback() {
798 #[cfg(feature = "log")]
799 log::trace!("retro_hw_context_reset_callback()");
800
801 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
802 let mut ctx = GenericContext::new(
803 &wrapper.environment_callback,
804 Arc::clone(&wrapper.interfaces),
805 );
806
807 return wrapper.core.on_hw_context_reset(&mut ctx);
808 }
809
810 panic!("retro_hw_context_reset_callback: Core has not been initialized yet!");
811}
812
813#[no_mangle]
815pub unsafe extern "C" fn retro_hw_context_destroyed_callback() {
816 #[cfg(feature = "log")]
817 log::trace!("retro_hw_context_destroyed_callback()");
818
819 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
820 let mut ctx = GenericContext::new(
821 &wrapper.environment_callback,
822 Arc::clone(&wrapper.interfaces),
823 );
824
825 return wrapper.core.on_hw_context_destroyed(&mut ctx);
826 }
827
828 panic!("retro_hw_context_destroyed_callback: Core has not been initialized yet!");
829}
830
831#[no_mangle]
833pub unsafe extern "C" fn retro_set_eject_state_callback(ejected: bool) -> bool {
834 #[cfg(feature = "log")]
835 log::trace!("retro_set_eject_state_callback(ejected = {ejected})");
836
837 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
838 return wrapper.core.on_set_eject_state(ejected);
839 }
840
841 panic!("retro_set_eject_state_callback: Core has not been initialized yet!");
842}
843
844#[no_mangle]
846pub unsafe extern "C" fn retro_get_eject_state_callback() -> bool {
847 #[cfg(feature = "log")]
848 log::trace!("retro_get_eject_state_callback()");
849
850 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
851 return wrapper.core.on_get_eject_state();
852 }
853
854 panic!("retro_get_eject_state_callback: Core has not been initialized yet!");
855}
856
857#[no_mangle]
859pub unsafe extern "C" fn retro_get_image_index_callback() -> ::std::os::raw::c_uint {
860 #[cfg(feature = "log")]
861 log::trace!("retro_get_image_index_callback()");
862
863 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
864 return wrapper.core.on_get_image_index();
865 }
866
867 panic!("retro_get_image_index_callback: Core has not been initialized yet!");
868}
869
870#[no_mangle]
872pub unsafe extern "C" fn retro_set_image_index_callback(index: ::std::os::raw::c_uint) -> bool {
873 #[cfg(feature = "log")]
874 log::trace!("retro_set_image_index_callback()");
875
876 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
877 return wrapper.core.on_set_image_index(index);
878 }
879
880 panic!("retro_set_image_index_callback: Core has not been initialized yet!");
881}
882
883#[no_mangle]
885pub unsafe extern "C" fn retro_get_num_images_callback() -> ::std::os::raw::c_uint {
886 #[cfg(feature = "log")]
887 log::trace!("retro_get_num_images_callback()");
888
889 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
890 return wrapper.core.on_get_num_images();
891 }
892
893 panic!("retro_get_num_images_callback: Core has not been initialized yet!");
894}
895
896#[no_mangle]
898pub unsafe extern "C" fn retro_replace_image_index_callback(
899 index: ::std::os::raw::c_uint,
900 info: *const retro_game_info,
901) -> bool {
902 #[cfg(feature = "log")]
903 log::trace!("retro_replace_image_index_callback(index = {index}, info = {info:#?})");
904
905 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
906 return wrapper.core.on_replace_image_index(index, info);
907 }
908
909 panic!("retro_replace_image_index_callback: Core has not been initialized yet!");
910}
911
912#[no_mangle]
914pub unsafe extern "C" fn retro_add_image_index_callback() -> bool {
915 #[cfg(feature = "log")]
916 log::trace!("retro_add_image_index_callback()");
917
918 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
919 return wrapper.core.on_add_image_index();
920 }
921
922 panic!("retro_add_image_index_callback: Core has not been initialized yet!");
923}
924
925#[no_mangle]
927pub unsafe extern "C" fn retro_set_initial_image_callback(
928 index: ::std::os::raw::c_uint,
929 path: *const ::std::os::raw::c_char,
930) -> bool {
931 #[cfg(feature = "log")]
932 log::trace!("retro_set_initial_image_callback(index = {index}, path = {path:#?})");
933
934 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
935 return wrapper
936 .core
937 .on_set_initial_image(index, CStr::from_ptr(path));
938 }
939
940 panic!("retro_set_initial_image_callback: Core has not been initialized yet!");
941}
942
943#[no_mangle]
945pub unsafe extern "C" fn retro_get_image_path_callback(
946 index: ::std::os::raw::c_uint,
947 path: *mut ::std::os::raw::c_char,
948 len: usize,
949) -> bool {
950 #[cfg(feature = "log")]
951 log::trace!("retro_get_image_path_callback(index = {index}, path = {path:#?}, len = {len})");
952
953 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
954 match wrapper.core.on_get_image_path(index) {
955 Some(image_path) => {
956 let image_path = image_path.as_bytes();
957 let buf = std::slice::from_raw_parts_mut(path as *mut u8, len);
958 let len = image_path.len().min(buf.len());
959
960 buf[..len].copy_from_slice(&image_path[..len]);
961 return true;
962 }
963 None => return false,
964 }
965 }
966
967 panic!("retro_get_image_path_callback: Core has not been initialized yet!");
968}
969
970#[no_mangle]
972pub unsafe extern "C" fn retro_get_image_label_callback(
973 index: ::std::os::raw::c_uint,
974 label: *mut ::std::os::raw::c_char,
975 len: usize,
976) -> bool {
977 #[cfg(feature = "log")]
978 log::trace!("retro_get_image_label_callback(index = {index}, label = {label:#?}, len = {len})");
979
980 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
981 match wrapper.core.on_get_image_label(index) {
982 Some(image_label) => {
983 let image_label = image_label.as_bytes();
984 let buf = std::slice::from_raw_parts_mut(label as *mut u8, len);
985 let len = image_label.len().min(buf.len());
986
987 buf[..len].copy_from_slice(&image_label[..len]);
988 return true;
989 }
990 None => return false,
991 }
992 }
993
994 panic!("retro_get_image_label_callback: Core has not been initialized yet!");
995}
996
997#[no_mangle]
999pub unsafe extern "C" fn retro_frame_time_callback_fn(usec: retro_usec_t) {
1000 #[cfg(feature = "log")]
1001 log::trace!("retro_frame_time_callback_fn(usec = {usec})");
1002
1003 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1004 wrapper.frame_delta = Some(usec);
1005 return;
1006 }
1007
1008 panic!("retro_frame_time_callback_fn: Core has not been initialized yet!");
1009}
1010
1011#[no_mangle]
1013pub unsafe extern "C" fn retro_audio_callback_fn() {
1014 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1019 let mut ctx = AudioContext {
1020 environment_callback: &wrapper.environment_callback,
1021 interfaces: Arc::clone(&wrapper.interfaces),
1022
1023 audio_sample_callback: &wrapper.audio_sample_callback,
1024 audio_sample_batch_callback: &wrapper.audio_sample_batch_callback,
1025 };
1026
1027 return wrapper.core.on_write_audio(&mut ctx);
1028 }
1029
1030 panic!("retro_audio_callback_fn: Core has not been initialized yet!");
1031}
1032
1033#[no_mangle]
1045pub unsafe extern "C" fn retro_audio_set_state_callback_fn(enabled: bool) {
1046 #[cfg(feature = "log")]
1047 log::trace!("retro_audio_set_state_callback_fn(enabled = {enabled})");
1048
1049 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1050 return wrapper.core.on_audio_set_state(enabled);
1051 }
1052
1053 panic!("retro_audio_set_state_callback_fn: Core has not been initialized yet!");
1054}
1055
1056#[no_mangle]
1058pub unsafe extern "C" fn retro_camera_frame_raw_framebuffer_callback(
1059 buffer: *const u32,
1060 width: ::std::os::raw::c_uint,
1061 height: ::std::os::raw::c_uint,
1062 pitch: usize,
1063) {
1064 let buffer_size = height as usize * pitch;
1065 let buffer = std::slice::from_raw_parts(buffer, buffer_size);
1066
1067 #[cfg(feature = "log")]
1068 log::trace!("retro_camera_frame_raw_framebuffer_callback(buffer = &[u32; {}], width = {width}, height = {height}, pitch = {pitch})", buffer.len());
1069
1070 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1071 return wrapper
1072 .core
1073 .on_camera_raw_framebuffer(buffer, width, height, pitch);
1074 }
1075
1076 panic!("retro_camera_frame_raw_framebuffer_callback: Core has not been initialized yet!");
1077}
1078
1079#[no_mangle]
1081pub unsafe extern "C" fn retro_camera_frame_opengl_texture_callback(
1082 texture_id: ::std::os::raw::c_uint,
1083 texture_target: ::std::os::raw::c_uint,
1084 affine: *const f32,
1085) {
1086 #[cfg(feature = "log")]
1087 log::trace!("retro_camera_frame_opengl_texture_callback(texture_id = {texture_id}, texture_target = {texture_target}, affine = {:#?})", std::slice::from_raw_parts(affine, 3 * 3));
1088
1089 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1090 let matrix = std::slice::from_raw_parts(affine, 3 * 3);
1092 let matrix: &[f32; 3 * 3] = matrix.try_into().unwrap();
1094
1095 return wrapper
1096 .core
1097 .on_camera_gl_texture(texture_id, texture_target, matrix);
1098 }
1099
1100 panic!("retro_camera_frame_opengl_texture_callback: Core has not been initialized yet!");
1101}
1102
1103#[no_mangle]
1105pub unsafe extern "C" fn retro_camera_initialized_callback() {
1106 #[cfg(feature = "log")]
1107 log::trace!("retro_camera_initialized_callback()");
1108
1109 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1110 let mut ctx = GenericContext::new(
1111 &wrapper.environment_callback,
1112 Arc::clone(&wrapper.interfaces),
1113 );
1114
1115 return wrapper.core.on_camera_initialized(&mut ctx);
1116 }
1117
1118 panic!("retro_camera_initialized_callback: Core has not been initialized yet!");
1119}
1120
1121#[no_mangle]
1123pub unsafe extern "C" fn retro_camera_deinitialized_callback() {
1124 #[cfg(feature = "log")]
1125 log::trace!("retro_camera_deinitialized_callback()");
1126
1127 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1128 let mut ctx = GenericContext::new(
1129 &wrapper.environment_callback,
1130 Arc::clone(&wrapper.interfaces),
1131 );
1132
1133 return wrapper.core.on_camera_deinitialized(&mut ctx);
1134 }
1135
1136 panic!("retro_camera_deinitialized_callback: Core has not been initialized yet!");
1137}
1138
1139#[no_mangle]
1141pub unsafe extern "C" fn retro_location_lifetime_status_initialized_callback() {
1142 #[cfg(feature = "log")]
1143 log::trace!("retro_location_lifetime_status_initialized_callback()");
1144
1145 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1146 let mut ctx = GenericContext::new(
1147 &wrapper.environment_callback,
1148 Arc::clone(&wrapper.interfaces),
1149 );
1150
1151 return wrapper
1152 .core
1153 .on_location_lifetime_status_initialized(&mut ctx);
1154 }
1155
1156 panic!(
1157 "retro_location_lifetime_status_initialized_callback: Core has not been initialized yet!"
1158 );
1159}
1160
1161#[no_mangle]
1163pub unsafe extern "C" fn retro_location_lifetime_status_deinitialized_callback() {
1164 #[cfg(feature = "log")]
1165 log::trace!("retro_location_lifetime_status_deinitialized_callback()");
1166
1167 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1168 let mut ctx = GenericContext::new(
1169 &wrapper.environment_callback,
1170 Arc::clone(&wrapper.interfaces),
1171 );
1172
1173 return wrapper
1174 .core
1175 .on_location_lifetime_status_deinitialized(&mut ctx);
1176 }
1177
1178 panic!(
1179 "retro_location_lifetime_status_deinitialized_callback: Core has not been initialized yet!"
1180 );
1181}
1182
1183#[no_mangle]
1185pub unsafe extern "C" fn retro_get_proc_address_callback(
1186 sym: *const ::std::os::raw::c_char,
1187) -> retro_proc_address_t {
1188 #[cfg(feature = "log")]
1189 log::trace!("retro_get_proc_address_callback({sym:#?})");
1190
1191 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1192 return wrapper.core.on_get_proc_address(CStr::from_ptr(sym));
1193 }
1194
1195 panic!("retro_get_proc_address_callback: Core has not been initialized yet!");
1196}
1197
1198#[no_mangle]
1200pub unsafe extern "C" fn retro_audio_buffer_status_callback_fn(
1201 active: bool,
1202 occupancy: ::std::os::raw::c_uint,
1203 underrun_likely: bool,
1204) {
1205 #[cfg(feature = "log")]
1206 log::trace!("retro_audio_buffer_status_callback_fn(active = {active}, occupancy = {occupancy}, underrun_likely = {underrun_likely})");
1207
1208 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1209 return wrapper
1210 .core
1211 .on_audio_buffer_status(active, occupancy, underrun_likely);
1212 }
1213
1214 panic!("retro_audio_buffer_status_callback_fn: Core has not been initialized yet!");
1215}
1216
1217#[no_mangle]
1219pub unsafe extern "C" fn retro_core_options_update_display_callback_fn() -> bool {
1220 #[cfg(feature = "log")]
1221 log::trace!("retro_core_options_update_display_callback_fn()");
1222
1223 if let Some(wrapper) = RETRO_INSTANCE.as_mut() {
1224 return wrapper.core.on_core_options_update_display();
1225 }
1226
1227 panic!("retro_core_options_update_display_callback_fn: Core has not been initialized yet!");
1228}