1#[doc(hidden)]
2pub extern crate libc;
3#[doc(hidden)]
4pub extern crate libretro_sys;
5
6use std::mem;
7use std::ptr;
8use std::slice;
9use std::ffi::{CStr, CString};
10use std::cmp::max;
11
12pub use libretro_sys::{PixelFormat, Region};
13
14pub struct CoreInfo {
15 library_name: CString,
16 library_version: CString,
17 supported_romfile_extensions: CString,
18 require_path_when_loading_roms: bool,
19 allow_frontend_to_extract_archives: bool
20}
21
22impl CoreInfo {
23 pub fn new( name: &str, version: &str ) -> CoreInfo {
24 CoreInfo {
25 library_name: CString::new( name ).unwrap(),
26 library_version: CString::new( version ).unwrap(),
27 supported_romfile_extensions: CString::new( "" ).unwrap(),
28 require_path_when_loading_roms: false,
29 allow_frontend_to_extract_archives: true
30 }
31 }
32
33 pub fn supports_roms_with_extension( mut self, mut extension: &str ) -> Self {
34 if extension.starts_with( "." ) {
35 extension = &extension[ 1.. ];
36 }
37
38 let mut string = CString::new( "" ).unwrap();
39 mem::swap( &mut string, &mut self.supported_romfile_extensions );
40
41 let mut vec = string.into_bytes();
42 if vec.is_empty() == false {
43 vec.push( '|' as u8 );
44 }
45
46 vec.extend_from_slice( extension.as_bytes() );
47
48 match extension {
49 "gz" | "xz" |
50 "zip" | "rar" | "7z" | "tar" | "tgz" | "txz" | "bz2" |
51 "tar.gz" | "tar.bz2"| "tar.xz" => {
52 self.allow_frontend_to_extract_archives = false;
53 },
54 _ => {}
55 }
56
57 self.supported_romfile_extensions = CString::new( vec ).unwrap();
58 self
59 }
60
61 pub fn requires_path_when_loading_roms( mut self ) -> Self {
62 self.require_path_when_loading_roms = true;
63 self
64 }
65}
66
67pub struct AudioVideoInfo {
68 width: u32,
69 height: u32,
70 max_width: u32,
71 max_height: u32,
72 frames_per_second: f64,
73 audio_sample_rate: f64,
74 aspect_ratio: Option< f32 >,
75 pixel_format: PixelFormat,
76 game_region: Option< Region >
77}
78
79impl AudioVideoInfo {
80 pub fn new() -> AudioVideoInfo {
81 AudioVideoInfo {
82 width: 0,
83 height: 0,
84 max_width: 0,
85 max_height: 0,
86 frames_per_second: 0.0,
87 aspect_ratio: None,
88 pixel_format: PixelFormat::RGB565,
89 audio_sample_rate: 0.0,
90 game_region: None
91 }
92 }
93
94 pub fn video( mut self, width: u32, height: u32, frames_per_second: f64, pixel_format: PixelFormat ) -> Self {
95 self.width = width;
96 self.height = height;
97 self.max_width = max( self.max_width, width );
98 self.max_height = max( self.max_height, height );
99 self.frames_per_second = frames_per_second;
100 self.pixel_format = pixel_format;
101 self
102 }
103
104 pub fn max_video_size( mut self, max_width: u32, max_height: u32 ) -> Self {
105 self.max_width = max( self.max_width, max_width );
106 self.max_height = max( self.max_height, max_height );
107 self
108 }
109
110 pub fn aspect_ratio( mut self, aspect_ratio: f32 ) -> Self {
111 self.aspect_ratio = Some( aspect_ratio );
112 self
113 }
114
115 pub fn audio( mut self, sample_rate: f64 ) -> Self {
116 self.audio_sample_rate = sample_rate;
117 self
118 }
119
120 pub fn region( mut self, game_region: Region ) -> Self {
121 self.game_region = Some( game_region );
122 self
123 }
124
125 fn infer_game_region( &self ) -> Region {
126 self.game_region.unwrap_or_else( || {
127 if self.frames_per_second > 59.0 {
128 Region::NTSC
129 } else {
130 Region::PAL
131 }
132 })
133 }
134}
135
136pub struct GameData {
137 path: Option< String >,
138
139 data: Option< &'static [u8] >
145}
146
147impl GameData {
148 pub fn path( &self ) -> Option< &str > {
149 self.path.as_ref().map( |path| &path[..] )
150 }
151
152 pub fn data( &self ) -> Option< &[u8] > {
153 self.data.map( |data| data as &[u8] )
154 }
155
156 pub fn is_empty( &self ) -> bool {
157 self.path().is_none() && self.data().is_none()
158 }
159}
160
161pub enum LoadGameResult {
162 Success( AudioVideoInfo ),
163 Failed( GameData )
164}
165
166#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
167pub enum JoypadButton {
168 A,
169 B,
170 X,
171 Y,
172 Select,
173 Start,
174 Up,
175 Down,
176 Left,
177 Right,
178 L1,
179 L2,
180 L3,
181 R1,
182 R2,
183 R3
184}
185
186pub trait Core: Default {
187 fn info() -> CoreInfo;
188 fn on_load_game( &mut self, game_data: GameData ) -> LoadGameResult;
189 fn on_unload_game( &mut self ) -> GameData;
190 fn on_run( &mut self, handle: &mut RuntimeHandle );
191 fn on_reset( &mut self );
192 fn save_memory( &mut self ) -> Option< &mut [u8] > {
193 None
194 }
195 fn rtc_memory( &mut self ) -> Option< &mut [u8] > {
196 None
197 }
198 fn system_memory( &mut self ) -> Option< &mut [u8] > {
199 None
200 }
201 fn video_memory( &mut self ) -> Option< &mut [u8] > {
202 None
203 }
204}
205
206static mut ENVIRONMENT_CALLBACK: Option< libretro_sys::EnvironmentFn > = None;
207
208#[doc(hidden)]
209pub struct Retro< B: Core > {
210 video_refresh_callback: Option< libretro_sys::VideoRefreshFn >,
211 audio_sample_callback: Option< libretro_sys::AudioSampleFn >,
212 audio_sample_batch_callback: Option< libretro_sys::AudioSampleBatchFn >,
213 input_poll_callback: Option< libretro_sys::InputPollFn >,
214 input_state_callback: Option< libretro_sys::InputStateFn >,
215
216 core: B,
217
218 is_game_loaded: bool,
219 av_info: AudioVideoInfo,
220 total_audio_samples_uploaded: usize
221}
222
223macro_rules! set_callback {
224 ($output: expr, $input: expr) => (
225 unsafe {
226 if $input == mem::transmute( 0 as usize ) {
227 $output = None;
228 } else {
229 $output = Some( $input );
230 }
231 }
232 )
233}
234
235impl< B: Core > Retro< B > {
236 fn new( core: B ) -> Self {
237 Retro {
238 video_refresh_callback: None,
239 audio_sample_callback: None,
240 audio_sample_batch_callback: None,
241 input_poll_callback: None,
242 input_state_callback: None,
243
244 core: core,
245
246 is_game_loaded: false,
247 av_info: AudioVideoInfo::new(),
248 total_audio_samples_uploaded: 0
249 }
250 }
251
252 #[must_use]
253 unsafe fn call_environment< T >( &mut self, command: libc::c_uint, pointer: &T ) -> Result< (), () > {
254 let ok = ENVIRONMENT_CALLBACK.unwrap()( command, mem::transmute( pointer ) );
255 if ok {
256 Ok(())
257 } else {
258 Err(())
259 }
260 }
261
262 pub fn on_get_system_info( info: *mut libretro_sys::SystemInfo ) {
263 assert_ne!( info, ptr::null_mut() );
264 let info = unsafe { &mut *info };
265
266 static mut INFO: Option< *const CoreInfo > = None;
269 let core_info = unsafe {
270 if INFO.is_none() {
271 INFO = Some( Box::into_raw( Box::new( B::info() ) ) );
272 }
273 INFO.map( |core_info| &*core_info ).unwrap()
274 };
275
276 info.library_name = core_info.library_name.as_ptr();
277 info.library_version = core_info.library_version.as_ptr();
278 info.valid_extensions = core_info.supported_romfile_extensions.as_ptr();
279 info.need_fullpath = core_info.require_path_when_loading_roms;
280 info.block_extract = core_info.allow_frontend_to_extract_archives == false;
281 }
282
283 pub fn on_set_environment( callback: libretro_sys::EnvironmentFn ) {
284 set_callback!( ENVIRONMENT_CALLBACK, callback );
285 }
286
287 pub fn on_set_video_refresh( &mut self, callback: libretro_sys::VideoRefreshFn ) {
288 set_callback!( self.video_refresh_callback, callback );
289 }
290
291 pub fn on_set_audio_sample( &mut self, callback: libretro_sys::AudioSampleFn ) {
292 set_callback!( self.audio_sample_callback, callback );
293 }
294
295 pub fn on_set_audio_sample_batch( &mut self, callback: libretro_sys::AudioSampleBatchFn ) {
296 set_callback!( self.audio_sample_batch_callback, callback );
297 }
298
299 pub fn on_set_input_poll( &mut self, callback: libretro_sys::InputPollFn ) {
300 set_callback!( self.input_poll_callback, callback );
301 }
302
303 pub fn on_set_input_state( &mut self, callback: libretro_sys::InputStateFn ) {
304 set_callback!( self.input_state_callback, callback );
305 }
306
307 pub fn on_get_system_av_info( &mut self, info: *mut libretro_sys::SystemAvInfo ) {
308 assert_ne!( info, ptr::null_mut() );
309 let info = unsafe { &mut *info };
310
311 info.geometry.base_width = self.av_info.width as libc::c_uint;
312 info.geometry.base_height = self.av_info.height as libc::c_uint;
313 info.geometry.max_width = self.av_info.max_width as libc::c_uint;
314 info.geometry.max_height = self.av_info.max_height as libc::c_uint;
315 info.geometry.aspect_ratio = self.av_info.aspect_ratio.unwrap_or( 0.0 );
316 info.timing.fps = self.av_info.frames_per_second;
317 info.timing.sample_rate = self.av_info.audio_sample_rate;
318 }
319
320 pub fn on_set_controller_port_device( &mut self, _port: libc::c_uint, _device: libc::c_uint ) {
321 }
322
323 pub fn on_reset( &mut self ) {
324 self.core.on_reset();
325 }
326
327 pub fn on_load_game( &mut self, game_info: *const libretro_sys::GameInfo ) -> bool {
328 assert_eq!( self.is_game_loaded, false );
329
330 let game_info = if game_info == ptr::null() {
331 None
332 } else {
333 Some( unsafe { &*game_info } )
334 };
335
336 let game_data = match game_info {
337 Some( game_info ) => {
338 let path = if game_info.path == ptr::null() {
339 None
340 } else {
341 unsafe {
342 CStr::from_ptr( game_info.path ).to_str().ok().map( |path| path.to_owned() )
343 }
344 };
345
346 let data = if game_info.data == ptr::null() && game_info.size == 0 {
347 None
348 } else {
349 unsafe {
350 Some( slice::from_raw_parts( game_info.data as *const u8, game_info.size ) )
351 }
352 };
353
354 GameData {
355 path: path,
356 data: data
357 }
358 },
359 None => {
360 GameData {
361 path: None,
362 data: None
363 }
364 }
365 };
366
367 let result = self.core.on_load_game( game_data );
368 match result {
369 LoadGameResult::Success( av_info ) => {
370 self.av_info = av_info;
371 unsafe {
372 let pixel_format = self.av_info.pixel_format;
373 self.call_environment( libretro_sys::ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format ).unwrap();
374 }
375
376 self.is_game_loaded = true;
377 true
378 },
379 LoadGameResult::Failed( _ ) => false
380 }
381 }
382
383 pub fn on_load_game_special( &mut self, _game_type: libc::c_uint, _info: *const libretro_sys::GameInfo, _num_info: libc::size_t ) -> bool {
384 false
385 }
386
387 pub fn on_run( &mut self ) {
388 let mut handle = RuntimeHandle {
389 video_refresh_callback: self.video_refresh_callback.unwrap(),
390 input_state_callback: self.input_state_callback.unwrap(),
391 audio_sample_batch_callback: self.audio_sample_batch_callback.unwrap(),
392 upload_video_frame_already_called: false,
393 audio_samples_uploaded: 0,
394
395 video_width: self.av_info.width,
396 video_height: self.av_info.height,
397 video_frame_bytes_per_pixel: match self.av_info.pixel_format {
398 PixelFormat::ARGB1555 | PixelFormat::RGB565 => 2,
399 PixelFormat::ARGB8888 => 4
400 }
401 };
402
403 unsafe {
404 self.input_poll_callback.unwrap()();
405 }
406
407 self.core.on_run( &mut handle );
408
409 self.total_audio_samples_uploaded += handle.audio_samples_uploaded;
410 let required_audio_sample_count_per_frame = (self.av_info.audio_sample_rate / self.av_info.frames_per_second) * 2.0;
411 assert!(
412 self.total_audio_samples_uploaded as f64 >= required_audio_sample_count_per_frame,
413 format!( "You need to upload at least {} audio samples each frame!", required_audio_sample_count_per_frame )
414 );
415
416 self.total_audio_samples_uploaded -= required_audio_sample_count_per_frame as usize;
417 }
418
419 pub fn on_serialize_size( &mut self ) -> libc::size_t {
420 0
421 }
422
423 pub fn on_serialize( &mut self, _data: *mut libc::c_void, _size: libc::size_t ) -> bool {
424 false
425 }
426
427 pub fn on_unserialize( &mut self, _data: *const libc::c_void, _size: libc::size_t ) -> bool {
428 false
429 }
430
431 pub fn on_cheat_reset( &mut self ) {
432 }
433
434 pub fn on_cheat_set( &mut self, _index: libc::c_uint, _is_enabled: bool, _code: *const libc::c_char ) {
435 }
436
437 pub fn on_unload_game( &mut self ) {
438 if self.is_game_loaded == false {
439 return;
440 }
441
442 let _ = self.core.on_unload_game();
443 }
444
445 pub fn on_get_region( &mut self ) -> libc::c_uint {
446 self.av_info.infer_game_region().to_uint()
447 }
448
449 fn memory_data( &mut self, id: libc::c_uint ) -> Option< &mut [u8] > {
450 match id {
451 libretro_sys::MEMORY_SAVE_RAM => self.core.save_memory(),
452 libretro_sys::MEMORY_RTC => self.core.rtc_memory(),
453 libretro_sys::MEMORY_SYSTEM_RAM => self.core.system_memory(),
454 libretro_sys::MEMORY_VIDEO_RAM => self.core.video_memory(),
455 _ => unreachable!(),
456 }
457 }
458
459 pub fn on_get_memory_data( &mut self, id: libc::c_uint ) -> *mut libc::c_void {
460 self.memory_data( id )
461 .map( |d| d as *mut _ as *mut libc::c_void )
462 .unwrap_or( ptr::null_mut() )
463 }
464
465 pub fn on_get_memory_size( &mut self, id: libc::c_uint ) -> libc::size_t {
466 self.memory_data( id )
467 .map( |d| d.len() as libc::size_t )
468 .unwrap_or( 0 )
469 }
470}
471
472pub struct RuntimeHandle {
473 video_refresh_callback: libretro_sys::VideoRefreshFn,
474 input_state_callback: libretro_sys::InputStateFn,
475 audio_sample_batch_callback: libretro_sys::AudioSampleBatchFn,
476 upload_video_frame_already_called: bool,
477 audio_samples_uploaded: usize,
478
479 video_width: u32,
480 video_height: u32,
481 video_frame_bytes_per_pixel: u32
482}
483
484impl RuntimeHandle {
485 pub fn upload_video_frame( &mut self, data: &[u8] ) {
486 assert!( self.upload_video_frame_already_called == false, "You can only call upload_video_frame() once per frame!" );
487
488 self.upload_video_frame_already_called = true;
489 let bytes = data.as_ptr() as *const libc::c_void;
490 let width = self.video_width as libc::c_uint;
491 let height = self.video_height as libc::c_uint;
492 let bytes_per_pixel = (self.video_width * self.video_frame_bytes_per_pixel) as usize;
493 unsafe {
494 (self.video_refresh_callback)( bytes, width, height, bytes_per_pixel );
495 }
496 }
497
498 pub fn upload_audio_frame( &mut self, data: &[i16] ) {
499 assert!( data.len() % 2 == 0, "Audio data must be in stereo!" );
500
501 self.audio_samples_uploaded += data.len();
502 unsafe {
503 (self.audio_sample_batch_callback)( data.as_ptr(), data.len() / 2 );
504 }
505 }
506
507 pub fn is_joypad_button_pressed( &mut self, port: u32, button: JoypadButton ) -> bool {
508 let device_id = match button {
509 JoypadButton::A => libretro_sys::DEVICE_ID_JOYPAD_A,
510 JoypadButton::B => libretro_sys::DEVICE_ID_JOYPAD_B,
511 JoypadButton::X => libretro_sys::DEVICE_ID_JOYPAD_X,
512 JoypadButton::Y => libretro_sys::DEVICE_ID_JOYPAD_Y,
513 JoypadButton::Start => libretro_sys::DEVICE_ID_JOYPAD_START,
514 JoypadButton::Select => libretro_sys::DEVICE_ID_JOYPAD_SELECT,
515 JoypadButton::Left => libretro_sys::DEVICE_ID_JOYPAD_LEFT,
516 JoypadButton::Right => libretro_sys::DEVICE_ID_JOYPAD_RIGHT,
517 JoypadButton::Up => libretro_sys::DEVICE_ID_JOYPAD_UP,
518 JoypadButton::Down => libretro_sys::DEVICE_ID_JOYPAD_DOWN,
519 JoypadButton::L1 => libretro_sys::DEVICE_ID_JOYPAD_L,
520 JoypadButton::L2 => libretro_sys::DEVICE_ID_JOYPAD_L2,
521 JoypadButton::L3 => libretro_sys::DEVICE_ID_JOYPAD_L3,
522 JoypadButton::R1 => libretro_sys::DEVICE_ID_JOYPAD_R,
523 JoypadButton::R2 => libretro_sys::DEVICE_ID_JOYPAD_R2,
524 JoypadButton::R3 => libretro_sys::DEVICE_ID_JOYPAD_R3
525 };
526
527 unsafe {
528 let value = (self.input_state_callback)( port, libretro_sys::DEVICE_JOYPAD, 0, device_id );
529 return value == 1;
530 }
531 }
532}
533
534#[doc(hidden)]
535pub fn construct< T: 'static + Core >() -> Retro< T > {
536 Retro::new( T::default() )
537}
538
539#[macro_export]
540macro_rules! libretro_core {
541 ($core: path) => (
542 #[doc(hidden)]
543 static mut LIBRETRO_INSTANCE: *mut $crate::Retro< $core > = 0 as *mut $crate::Retro< $core >;
544
545 #[doc(hidden)]
546 #[no_mangle]
547 pub extern "C" fn retro_api_version() -> $crate::libc::c_uint {
548 return $crate::libretro_sys::API_VERSION;
549 }
550
551 #[doc(hidden)]
552 #[no_mangle]
553 pub unsafe extern "C" fn retro_init() {
554 assert_eq!( LIBRETRO_INSTANCE, 0 as *mut _ );
555 let retro = $crate::construct::< $core >();
556 LIBRETRO_INSTANCE = Box::into_raw( Box::new( retro ) );
557 }
558
559 #[doc(hidden)]
560 #[no_mangle]
561 pub unsafe extern "C" fn retro_deinit() {
562 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
563 let instance = Box::from_raw( LIBRETRO_INSTANCE );
564 LIBRETRO_INSTANCE = 0 as *mut _;
565 ::std::mem::drop( instance );
566 }
567
568 #[doc(hidden)]
569 #[no_mangle]
570 pub unsafe extern "C" fn retro_set_environment( callback: $crate::libretro_sys::EnvironmentFn ) {
571 $crate::Retro::< $core >::on_set_environment( callback )
572 }
573
574 #[doc(hidden)]
575 #[no_mangle]
576 pub unsafe extern "C" fn retro_set_video_refresh( callback: $crate::libretro_sys::VideoRefreshFn ) {
577 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
578 (&mut *LIBRETRO_INSTANCE).on_set_video_refresh( callback )
579 }
580
581 #[doc(hidden)]
582 #[no_mangle]
583 pub unsafe extern "C" fn retro_set_audio_sample( callback: $crate::libretro_sys::AudioSampleFn ) {
584 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
585 (&mut *LIBRETRO_INSTANCE).on_set_audio_sample( callback )
586 }
587
588 #[doc(hidden)]
589 #[no_mangle]
590 pub unsafe extern "C" fn retro_set_audio_sample_batch( callback: $crate::libretro_sys::AudioSampleBatchFn ) {
591 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
592 (&mut *LIBRETRO_INSTANCE).on_set_audio_sample_batch( callback )
593 }
594
595 #[doc(hidden)]
596 #[no_mangle]
597 pub unsafe extern "C" fn retro_set_input_poll( callback: $crate::libretro_sys::InputPollFn ) {
598 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
599 (&mut *LIBRETRO_INSTANCE).on_set_input_poll( callback )
600 }
601
602 #[doc(hidden)]
603 #[no_mangle]
604 pub unsafe extern "C" fn retro_set_input_state( callback: $crate::libretro_sys::InputStateFn ) {
605 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
606 (&mut *LIBRETRO_INSTANCE).on_set_input_state( callback )
607 }
608
609 #[doc(hidden)]
610 #[no_mangle]
611 pub extern "C" fn retro_get_system_info( info: *mut $crate::libretro_sys::SystemInfo ) {
612 $crate::Retro::< $core >::on_get_system_info( info )
613 }
614
615 #[doc(hidden)]
616 #[no_mangle]
617 pub unsafe extern "C" fn retro_get_system_av_info( info: *mut $crate::libretro_sys::SystemAvInfo ) {
618 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
619 (&mut *LIBRETRO_INSTANCE).on_get_system_av_info( info )
620 }
621
622 #[doc(hidden)]
623 #[no_mangle]
624 pub unsafe extern "C" fn retro_set_controller_port_device( port: $crate::libc::c_uint, device: $crate::libc::c_uint ) {
625 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
626 (&mut *LIBRETRO_INSTANCE).on_set_controller_port_device( port, device )
627 }
628
629 #[doc(hidden)]
630 #[no_mangle]
631 pub unsafe extern "C" fn retro_reset() {
632 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
633 (&mut *LIBRETRO_INSTANCE).on_reset()
634 }
635
636 #[doc(hidden)]
637 #[no_mangle]
638 pub unsafe extern "C" fn retro_run() {
639 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
640 (&mut *LIBRETRO_INSTANCE).on_run()
641 }
642
643 #[doc(hidden)]
644 #[no_mangle]
645 pub unsafe extern "C" fn retro_serialize_size() -> $crate::libc::size_t {
646 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
647 (&mut *LIBRETRO_INSTANCE).on_serialize_size()
648 }
649
650 #[doc(hidden)]
651 #[no_mangle]
652 pub unsafe extern "C" fn retro_serialize( data: *mut $crate::libc::c_void, size: $crate::libc::size_t ) -> bool {
653 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
654 (&mut *LIBRETRO_INSTANCE).on_serialize( data, size )
655 }
656
657 #[doc(hidden)]
658 #[no_mangle]
659 pub unsafe extern "C" fn retro_unserialize( data: *const $crate::libc::c_void, size: $crate::libc::size_t ) -> bool {
660 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
661 (&mut *LIBRETRO_INSTANCE).on_unserialize( data, size )
662 }
663
664 #[doc(hidden)]
665 #[no_mangle]
666 pub unsafe extern "C" fn retro_cheat_reset() {
667 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
668 (&mut *LIBRETRO_INSTANCE).on_cheat_reset()
669 }
670
671 #[doc(hidden)]
672 #[no_mangle]
673 pub unsafe extern "C" fn retro_cheat_set( index: $crate::libc::c_uint, is_enabled: bool, code: *const $crate::libc::c_char ) {
674 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
675 (&mut *LIBRETRO_INSTANCE).on_cheat_set( index, is_enabled, code )
676 }
677
678 #[doc(hidden)]
679 #[no_mangle]
680 pub unsafe extern "C" fn retro_load_game( game: *const $crate::libretro_sys::GameInfo ) -> bool {
681 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
682 (&mut *LIBRETRO_INSTANCE).on_load_game( game )
683 }
684
685 #[doc(hidden)]
686 #[no_mangle]
687 pub unsafe extern "C" fn retro_load_game_special( game_type: $crate::libc::c_uint, info: *const $crate::libretro_sys::GameInfo, num_info: $crate::libc::size_t ) -> bool {
688 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
689 (&mut *LIBRETRO_INSTANCE).on_load_game_special( game_type, info, num_info )
690 }
691
692 #[doc(hidden)]
693 #[no_mangle]
694 pub unsafe extern "C" fn retro_unload_game() {
695 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
696 (&mut *LIBRETRO_INSTANCE).on_unload_game()
697 }
698
699 #[doc(hidden)]
700 #[no_mangle]
701 pub unsafe extern "C" fn retro_get_region() -> $crate::libc::c_uint {
702 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
703 (&mut *LIBRETRO_INSTANCE).on_get_region()
704 }
705
706 #[doc(hidden)]
707 #[no_mangle]
708 pub unsafe extern "C" fn retro_get_memory_data( id: $crate::libc::c_uint ) -> *mut $crate::libc::c_void {
709 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
710 (&mut *LIBRETRO_INSTANCE).on_get_memory_data( id )
711 }
712
713 #[doc(hidden)]
714 #[no_mangle]
715 pub unsafe extern "C" fn retro_get_memory_size( id: $crate::libc::c_uint ) -> $crate::libc::size_t {
716 assert_ne!( LIBRETRO_INSTANCE, 0 as *mut _ );
717 (&mut *LIBRETRO_INSTANCE).on_get_memory_size( id )
718 }
719 )
720}