1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
// hello-rs-libretro - A minimal hello world libretro core in Rust
// Copyright (C) 2025 David Brinovec
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::;
/// Returns the version of the libretro API this core was compiled against.
///
/// This is the first function RetroArch calls when loading a core. RetroArch
/// uses the returned value to verify ABI compatibility — if the version
/// doesn't match what RetroArch expects, it will refuse to load the core.
///
/// Always returns `1`, which is the value of `RETRO_API_VERSION` in
/// `libretro.h`. This value has been stable for many years and is unlikely
/// to change.
pub extern "C"
/// Provides static information about this core to RetroArch.
///
/// Called by RetroArch shortly after [`retro_api_version`] to identify the
/// core and learn about its content requirements. The information returned
/// here should be static — if dynamic allocation is used, the memory must
/// remain valid until [`retro_deinit`] is called.
///
/// This core uses `c""` string literals which produce static null-terminated
/// C strings with no allocation required.
///
/// # Arguments
/// * `info` — pointer to a [`RetroSystemInfo`] struct allocated by RetroArch
/// that this function fills in.
///
/// # Fields set
/// * `library_name` — the name of this core as it appears in RetroArch's UI.
/// * `library_version` — the version string shown alongside the name.
/// * `valid_extensions` — comma-separated list of file extensions this core
/// can load. Empty since this core requires no content.
/// * `need_fullpath` — if true, RetroArch passes the file path rather than
/// loading the file into memory. False since we require no content.
/// * `block_extract` — if true, RetroArch will not extract archive files
/// before passing them to the core. False since we require no content.
pub extern "C"
/// Provides audio and video parameters for this core to RetroArch.
///
/// Called by RetroArch after [`retro_load_game`] to determine how to set up
/// its video and audio systems. The values returned here must be consistent
/// with the pixel format set via [`RETRO_ENVIRONMENT_SET_PIXEL_FORMAT`] in
/// [`retro_set_environment`].
///
/// # Arguments
/// * `info` — pointer to a [`RetroSystemAvInfo`] struct allocated by RetroArch
/// that this function fills in.
///
/// # Fields set
/// * `geometry.base_width` / `geometry.base_height` — the core's native
/// resolution. RetroArch will scale this to fit the display.
/// * `geometry.max_width` / `geometry.max_height` — the maximum resolution
/// the core will ever produce. Must be at least as large as base dimensions.
/// * `geometry.aspect_ratio` — the intended display aspect ratio. Set to
/// `16.0 / 9.0` for widescreen. A value of `0.0` tells RetroArch to
/// calculate it from the base dimensions instead.
/// * `timing.fps` — the target frame rate. RetroArch uses this to drive its
/// main loop timing.
/// * `timing.sample_rate` — the audio sample rate in Hz. Must match the
/// rate at which samples are generated in [`retro_run`].
pub extern "C"
/// Receives the environment callback from RetroArch and uses it to declare
/// core capabilities.
///
/// This is the first function RetroArch calls after loading the core, even
/// before [`retro_init`]. The environment callback is stored in
/// [`ENVIRONMENT_CALLBACK`] for use throughout the core's lifetime.
///
/// This function makes two environment calls:
/// * [`RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME`] — declares that this core
/// can run without any content loaded, allowing the user to start it
/// directly from RetroArch's Load Core menu without selecting a ROM.
/// * [`RETRO_ENVIRONMENT_SET_PIXEL_FORMAT`] — declares that this core will
/// submit video frames in XRGB8888 format (32 bits per pixel, 8 bits per
/// channel). Without this call RetroArch assumes the legacy XRGB1555
/// format and colors will be incorrect.
///
/// # Arguments
/// * `cb` — the environment callback function pointer provided by RetroArch.
/// Accepts a command number and a pointer to command-specific data.
pub extern "C"
/// Receives the video refresh callback from RetroArch.
///
/// Called by RetroArch during startup before [`retro_init`]. The callback
/// is stored in [`VIDEO_REFRESH_CALLBACK`] and called once per frame inside
/// [`retro_run`] to submit the completed pixel buffer to RetroArch for
/// display.
///
/// See [`VIDEO_REFRESH_CALLBACK`] for a description of the callback's
/// arguments.
///
/// # Arguments
/// * `cb` — the video refresh callback function pointer provided by RetroArch.
pub extern "C"
/// Receives the single-sample audio callback from RetroArch.
///
/// Called by RetroArch during startup before [`retro_init`]. Stored in
/// [`AUDIO_SAMPLE_CALLBACK`] but not used by this core — audio is submitted
/// in batches via [`AUDIO_SAMPLE_BATCH_CALLBACK`] instead, which is more
/// efficient. This callback must still be accepted and stored per the
/// libretro spec.
///
/// See [`AUDIO_SAMPLE_CALLBACK`] for a description of the callback's
/// arguments.
///
/// # Arguments
/// * `cb` — the single-sample audio callback function pointer provided by
/// RetroArch.
pub extern "C"
/// Receives the batched audio callback from RetroArch.
///
/// Called by RetroArch during startup before [`retro_init`]. The callback
/// is stored in [`AUDIO_SAMPLE_BATCH_CALLBACK`] and called once per frame
/// inside [`retro_run`] to submit a buffer of interleaved stereo PCM samples
/// to RetroArch for playback.
///
/// This is the preferred audio submission method for this core. Submitting
/// samples in batches is more efficient than [`AUDIO_SAMPLE_CALLBACK`]
/// since it crosses the FFI boundary only once per frame rather than once
/// per sample.
///
/// See [`AUDIO_SAMPLE_BATCH_CALLBACK`] for a description of the callback's
/// arguments.
///
/// # Arguments
/// * `cb` — the batched audio callback function pointer provided by RetroArch.
pub extern "C"
/// Receives the input poll callback from RetroArch.
///
/// Called by RetroArch during startup before [`retro_init`]. The callback
/// is stored in [`INPUT_POLL_CALLBACK`] and called once at the start of
/// each frame in [`retro_run`] before any input state is read. Calling it
/// signals RetroArch to snapshot the current state of all input devices.
///
/// See [`INPUT_POLL_CALLBACK`] for further details on correct usage.
///
/// # Arguments
/// * `cb` — the input poll callback function pointer provided by RetroArch.
pub extern "C"
/// Receives the input state callback from RetroArch.
///
/// Called by RetroArch during startup before [`retro_init`]. The callback
/// is stored in [`INPUT_STATE_CALLBACK`] and called inside [`retro_run`]
/// after [`INPUT_POLL_CALLBACK`] has been called to query the state of
/// specific buttons or axes.
///
/// See [`INPUT_STATE_CALLBACK`] for a full description of the callback's
/// arguments and return value.
///
/// # Arguments
/// * `cb` — the input state callback function pointer provided by RetroArch.
pub extern "C"
/// Initializes the core.
///
/// Called by RetroArch once after all callbacks have been set via the
/// `retro_set_*` functions and before [`retro_load_game`]. This is where
/// the core allocates and initializes its state.
///
/// This function creates the global [`CORE`] instance via [`HelloCore::new`]
/// and sets the pixel format to XRGB8888 via [`ENVIRONMENT_CALLBACK`]. The
/// pixel format is also set in [`retro_set_environment`] but is set again
/// here to ensure it is applied regardless of the order RetroArch calls
/// these functions.
pub extern "C"
/// Loads content for this core.
///
/// Called by RetroArch after [`retro_init`] when the user selects content
/// to run, or immediately after [`retro_init`] with a null pointer if no
/// content is selected and the core declared support for no-content mode
/// via [`RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME`].
///
/// This core does not load any content — it runs entirely without a ROM or
/// any other input file. The `game` pointer is therefore always null and is
/// intentionally ignored.
///
/// # Arguments
/// * `game` — pointer to a [`RetroGameInfo`] struct describing the content
/// to load, or null if running in no-content mode.
///
/// # Returns
/// `true` if the core loaded successfully, `false` to signal a fatal error
/// that prevents the core from running.
pub extern "C"
/// Runs the core for one video frame.
///
/// This is the core's main loop, called by RetroArch once per frame at the
/// rate specified in [`retro_get_system_av_info`]. Each call to this function
/// must do three things in order:
///
/// 1. **Poll input** — call [`INPUT_POLL_CALLBACK`] to snapshot controller
/// state, then read any needed inputs via [`INPUT_STATE_CALLBACK`]. Input
/// must be polled before it is read.
/// 2. **Submit a video frame** — build a pixel buffer and pass it to
/// [`VIDEO_REFRESH_CALLBACK`]. Exactly one video frame must be submitted
/// per call.
/// 3. **Submit audio** — generate audio samples for this frame and pass them
/// to [`AUDIO_SAMPLE_BATCH_CALLBACK`]. The number of samples submitted
/// should match the sample rate divided by the frame rate — at 48000 Hz
/// and 60 fps this is 800 stereo frames per call.
///
/// This core renders an animated crosshatch pattern whose color cycles over
/// time and pans diagonally across the screen. Audio is a sweeping tone
/// whose waveform can be cycled between [`Waveform::Square`],
/// [`Waveform::Pulse`], and [`Waveform::Sawtooth`] by pressing a button.
pub extern "C"
/// Deinitializes the core and frees all resources.
///
/// Called by RetroArch after [`retro_unload_game`] when the core is being
/// shut down. This is the counterpart to [`retro_init`] — anything
/// allocated there should be freed here.
///
/// Drops the global [`CORE`] instance by setting it to `None`, which
/// triggers the [`Drop`] implementation for [`HelloCore`] and frees all
/// associated state. After this function returns the core must be in a
/// clean state and ready to be initialized again via [`retro_init`] if
/// RetroArch chooses to do so.
pub extern "C"
/// Unloads the current content.
///
/// Called by RetroArch before [`retro_deinit`] when the user closes the
/// current content or before loading new content. This is the counterpart
/// to [`retro_load_game`] — anything allocated during content loading
/// should be freed here.
///
/// Since this core loads no content in [`retro_load_game`], there is
/// nothing to unload here.
pub extern "C"
/// Returns the region of the content currently loaded.
///
/// Called by RetroArch to determine whether the core is running in NTSC
/// or PAL mode, which affects timing and display characteristics. Returns
/// `0` for NTSC (60 Hz) or `1` for PAL (50 Hz).
///
/// This core always returns `0` (NTSC) since it has no region-specific
/// behavior and targets 60 fps as declared in [`retro_get_system_av_info`].
pub extern "C"
/// Returns the number of bytes required to serialize the core's state.
///
/// Called by RetroArch when the user requests a save state. The returned
/// value tells RetroArch how much memory to allocate before calling
/// [`retro_serialize`].
///
/// This core does not support save states and returns `0` to opt out.
/// Returning `0` causes RetroArch to skip the save state operation
/// entirely without calling [`retro_serialize`].
pub extern "C"
/// Serializes the core's current state into a buffer.
///
/// Called by RetroArch when the user requests a save state, immediately
/// after allocating a buffer of [`retro_serialize_size`] bytes. The core
/// should write its complete state into `data` such that it can be fully
/// restored later via [`retro_unserialize`].
///
/// This core does not support save states and returns `false` to signal
/// failure. In practice this function will never be called since
/// [`retro_serialize_size`] returns `0`.
///
/// # Arguments
/// * `data` — pointer to a buffer of [`retro_serialize_size`] bytes
/// allocated by RetroArch to receive the serialized state.
/// * `size` — the size of the buffer in bytes, equal to the value
/// returned by [`retro_serialize_size`].
///
/// # Returns
/// `true` if serialization succeeded, `false` if it failed.
pub extern "C"
/// Restores the core's state from a previously serialized buffer.
///
/// Called by RetroArch when the user loads a save state. The core should
/// read its complete state from `data` and restore itself to exactly the
/// state it was in when [`retro_serialize`] produced that buffer.
///
/// This core does not support save states and returns `false` to signal
/// failure. In practice this function will never be called since
/// [`retro_serialize_size`] returns `0`.
///
/// # Arguments
/// * `data` — pointer to a buffer containing a previously serialized state
/// produced by [`retro_serialize`].
/// * `size` — the size of the buffer in bytes.
///
/// # Returns
/// `true` if the state was restored successfully, `false` if it failed.
pub extern "C"
/// Returns a pointer to a region of the core's memory.
///
/// Called by RetroArch to expose internal memory regions for use by
/// external tools such as cheat engines, memory watchers, and
/// RetroAchievements. The `id` argument identifies which memory region
/// is being requested.
///
/// Common memory region IDs:
/// * `0` — Save RAM (SRAM)
/// * `1` — Real-time clock (RTC)
/// * `2` — System RAM
/// * `3` — Video RAM
///
/// This core does not expose any memory regions and returns a null pointer
/// for all IDs. [`retro_get_memory_size`] correspondingly returns `0`.
///
/// # Arguments
/// * `id` — identifies which memory region RetroArch is requesting.
///
/// # Returns
/// A pointer to the requested memory region, or null if the region is
/// not available.
pub extern "C"
/// Returns the size in bytes of a region of the core's memory.
///
/// Called by RetroArch alongside [`retro_get_memory_data`] to determine
/// the size of a memory region exposed by the core. The `id` argument
/// identifies which memory region is being queried and corresponds to
/// the same IDs described in [`retro_get_memory_data`].
///
/// This core does not expose any memory regions and returns `0` for all
/// IDs, consistent with [`retro_get_memory_data`] returning a null pointer.
///
/// # Arguments
/// * `id` — identifies which memory region RetroArch is querying.
///
/// # Returns
/// The size in bytes of the requested memory region, or `0` if the region
/// is not available.
pub extern "C"
/// Resets all active cheat codes.
///
/// Called by RetroArch when the user clears all cheats. The core should
/// disable any currently active cheat effects and restore normal behavior.
///
/// This core does not support cheats and this function is a no-op.
pub extern "C"
/// Applies or removes a single cheat code.
///
/// Called by RetroArch when the user enables or disables a specific cheat.
/// The core should apply or remove the effect of the cheat identified by
/// `index`.
///
/// This core does not support cheats and this function is a no-op.
///
/// # Arguments
/// * `index` — the position of this cheat in RetroArch's cheat list.
/// * `enabled` — `true` if the cheat should be applied, `false` if it
/// should be removed.
/// * `code` — a null-terminated C string containing the cheat code in
/// whatever format the core expects.
pub extern "C"
/// Notifies the core that a controller type has been set for a port.
///
/// Called by RetroArch when the user changes the controller type assigned
/// to a specific port, for example switching from a standard RetroPad to
/// an analog controller or a lightgun. The core should adjust its input
/// handling accordingly.
///
/// This core does not distinguish between controller types and this
/// function is a no-op. All input is read as a standard RetroPad via
/// [`INPUT_STATE_CALLBACK`].
///
/// # Arguments
/// * `port` — the controller port being configured (0 = player 1, etc.)
/// * `device` — the device type being assigned to the port. Common values
/// are `1` for RetroPad and `5` for analog controller.
pub extern "C"
/// Resets the core to its initial state.
///
/// Called by RetroArch when the user triggers a soft reset, equivalent to
/// pressing the reset button on the original hardware. The core should
/// return to the same state it was in immediately after [`retro_load_game`]
/// returned, without reinitializing everything from scratch as
/// [`retro_init`] would.
///
/// This core has no meaningful reset behavior — the animated crosshatch
/// and audio sweep have no concept of a starting state worth restoring.
/// This function is a no-op.
pub extern "C"
/// Loads a special type of content requiring multiple ROM files.
///
/// Called by RetroArch instead of [`retro_load_game`] for content types
/// that require more than one file simultaneously, such as multi-disc
/// games, super game boy style hardware combinations, or other scenarios
/// where a single ROM file is insufficient.
///
/// This core does not support any special content types and returns `false`
/// to signal failure for all requests.
///
/// # Arguments
/// * `game_type` — identifies the type of special content being loaded.
/// The meaning of specific values is defined by each core.
/// * `info` — pointer to an array of [`RetroGameInfo`] structs, one per
/// required file, with `num_info` entries.
/// * `num_info` — the number of [`RetroGameInfo`] entries in `info`.
///
/// # Returns
/// `true` if the content loaded successfully, `false` if it failed or
/// is not supported.
pub extern "C"