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
//! Module for dealing with the load-state of Nintendo DS overlays.
use crate::ffi;
/// This represents a promise to the compiler that while a reference
/// to this struct exists, the overlay N is loaded.
///
/// This is used as a parameter in functions that need a given overlay to be loaded.
///
/// Dropping the lease does *not* unload an overlay, but you can use
/// the [`Self::unload`] method on a lease to do so.
///
/// You can clone a lease, but you will have the responsibility to make
/// sure the overlay is not unloaded while clone lease is in use too.
#[derive(Clone)]
pub struct OverlayLoadLease<const N: u32>(());
impl<const N: u32> OverlayLoadLease<N> {
/// Gets a lease on a loaded overlay.
///
/// This is a runtime checked version of `acquire_unchecked`.
/// It will panic if the overlay is not loaded.
///
/// # Important
/// Even though this function is marked as safe, since it
/// checks if the overlay is loaded, you still need to make
/// sure the overlay is not unloaded during the lifetime
/// of the returned object.
pub fn acquire() -> Self {
if !Self::is_loaded() {
panic!("Overlay {} is not loaded.", N);
}
Self(())
}
/// Gets a lease on a loaded overlay.
///
/// # Safety
/// You need to make sure the overlay is actually loaded and won't
/// get unloaded during the lifetime of the returned object.
pub unsafe fn acquire_unchecked() -> Self {
Self(())
}
/// Checks if the overlay is loaded.
pub fn is_loaded() -> bool {
unsafe { ffi::OverlayIsLoaded(Self::group_id()) > 0 }
}
/// Loads the given overlay if it isn't already loaded.
///
/// # Safety
/// This will change how memory is mapped. You will need to make
/// sure there are no conflicts with other overlays and that all
/// memory currently referenced will still be valid after this call.
pub unsafe fn load() -> Self {
if !Self::is_loaded() {
ffi::LoadOverlay(Self::group_id())
}
Self(())
}
/// Unloads the overlay.
///
/// # Safety
/// This will render all still existing leases on the overlay invalid.
/// You need to make sure that all leases are dropped.
pub unsafe fn unload(self) {
ffi::UnloadOverlay(Self::group_id());
}
/// Returns the group ID of the overlay. This supports all game builtin overlays.
/// Panics if no mapping is known.
pub fn group_id() -> u32 {
match N {
0 => ffi::overlay_group_id::OGROUP_OVERLAY_0,
1 => ffi::overlay_group_id::OGROUP_OVERLAY_1,
2 => ffi::overlay_group_id::OGROUP_OVERLAY_2,
3 => ffi::overlay_group_id::OGROUP_OVERLAY_3,
4 => ffi::overlay_group_id::OGROUP_OVERLAY_4,
5 => ffi::overlay_group_id::OGROUP_OVERLAY_5,
6 => ffi::overlay_group_id::OGROUP_OVERLAY_6,
7 => ffi::overlay_group_id::OGROUP_OVERLAY_7,
8 => ffi::overlay_group_id::OGROUP_OVERLAY_8,
9 => ffi::overlay_group_id::OGROUP_OVERLAY_9,
10 => ffi::overlay_group_id::OGROUP_OVERLAY_10,
11 => ffi::overlay_group_id::OGROUP_OVERLAY_11,
12 => ffi::overlay_group_id::OGROUP_OVERLAY_12,
13 => ffi::overlay_group_id::OGROUP_OVERLAY_13,
14 => ffi::overlay_group_id::OGROUP_OVERLAY_14,
15 => ffi::overlay_group_id::OGROUP_OVERLAY_15,
16 => ffi::overlay_group_id::OGROUP_OVERLAY_16,
17 => ffi::overlay_group_id::OGROUP_OVERLAY_17,
18 => ffi::overlay_group_id::OGROUP_OVERLAY_18,
19 => ffi::overlay_group_id::OGROUP_OVERLAY_19,
20 => ffi::overlay_group_id::OGROUP_OVERLAY_20,
21 => ffi::overlay_group_id::OGROUP_OVERLAY_21,
22 => ffi::overlay_group_id::OGROUP_OVERLAY_22,
23 => ffi::overlay_group_id::OGROUP_OVERLAY_23,
24 => ffi::overlay_group_id::OGROUP_OVERLAY_24,
25 => ffi::overlay_group_id::OGROUP_OVERLAY_25,
26 => ffi::overlay_group_id::OGROUP_OVERLAY_26,
27 => ffi::overlay_group_id::OGROUP_OVERLAY_27,
28 => ffi::overlay_group_id::OGROUP_OVERLAY_28,
29 => ffi::overlay_group_id::OGROUP_OVERLAY_29,
30 => ffi::overlay_group_id::OGROUP_OVERLAY_30,
31 => ffi::overlay_group_id::OGROUP_OVERLAY_31,
32 => ffi::overlay_group_id::OGROUP_OVERLAY_32,
33 => ffi::overlay_group_id::OGROUP_OVERLAY_33,
34 => ffi::overlay_group_id::OGROUP_OVERLAY_34,
35 => ffi::overlay_group_id::OGROUP_OVERLAY_35,
_ => panic!("No known overlay group for overlay."),
}
}
}
/// Trait for all structs that require a lease to be created (but nothing else).
pub trait CreatableWithLease<const N: u32>
where
Self: Sized,
{
/// Internal constructor that needs to be implemented. Don't call this directly.
#[doc(hidden)]
fn _create(lease: OverlayLoadLease<N>) -> Self;
/// Create a new instance by providing a lease.
///
/// # Important
/// Overlay N must not be unloaded during the lifetime of the returned object.
fn new(lease: OverlayLoadLease<N>) -> Self {
Self::_create(lease)
}
/// Create a new instance by checking if the overlay
/// is loaded and acquiring a lease on it.
/// This will panic if the overlay is not loaded.
///
/// # Important
/// Overlay N must not be unloaded during the lifetime of the returned object.
fn new_checked() -> Self {
Self::_create(OverlayLoadLease::<N>::acquire())
}
/// Create a new lease.
///
/// # Safety
/// This function is unsafe because it does not check if the overlay is loaded.
/// You need to make sure that the overlay is loaded before calling this function,
/// and additionally ensure that during the lifetime of this object the overlay
/// is not unloaded.
unsafe fn new_unchecked() -> Self {
Self::_create(OverlayLoadLease::<N>::acquire_unchecked())
}
/// Returns a reference to the overlay lease.
fn lease(&self) -> &OverlayLoadLease<N>;
}